API reference · Nanook 3.x

Logger

Generated on 2026-10-03 from docs/api/logger.md in the repository (commit f26b8022e0f8 of 2026-10-03) by tools/build-api-v3.py. The text is the repository's, not edited here. The samples with imports type-check against the published package 3.3.1; no known deviations.

The logger module provides a logging interface used by all Nanook components and an in-memory implementation suitable for development, testing, and production use.

import {
  LoggerInterface,
  LoggerMemory,
  getLoggerMemory
} from '@xhubio/nanook-table'
import type { LogEntry, LogMessageType } from '@xhubio/nanook-table'

LoggerInterface

The base class that defines the logging contract (a concrete class, not an interface, despite the name). All Nanook components accept a LoggerInterface and use it for diagnostic output. Extend it to integrate with any logging framework (Winston, Pino, console, etc.). On its own it discards every message.

Log Levels

Log levels are ordered by severity. Setting the logger to a given level means it will only output messages at that level or higher. The default level is error: debug, info and warning messages are dropped unless you lower it.

Level Numeric Value Description
debug 0 Detailed diagnostic information
info 1 General informational messages
warning 2 Potentially problematic situations
error 3 Error conditions that allow continued operation (the default level)
fatal 4 Severe errors that may cause the process to abort

Properties

Property Type Description
level set: string | number, get: string The current log level. Messages below this level are suppressed. Set it as a string ('debug', 'info', etc.) or a number (0--4); reading it returns the name. Default 'error'

Methods

debug(message: string | object): void

Logs a message at the debug level (numeric value 0).

logger.debug('Processing table: LoginTests')
logger.debug({ table: 'LoginTests', testcases: 5 })

info(message: string | object): void

Logs a message at the info level (numeric value 1).

logger.info('File loaded successfully')

warning(message: string | object): void

Logs a message at the warning level (numeric value 2).

logger.warning('Sheet "OldFormat" uses deprecated section type')

error(message: string | object): void

Logs a message at the error level (numeric value 3).

logger.error('Generator "myGen" returned no value')

fatal(message: string | object): void

Logs a message at the fatal level (numeric value 4).

logger.fatal('Cannot open file: tests.xlsx')

The log methods are synchronous. The helpers getLevelNumber(), getLevelName(), getLogEntry() and getTime() are protected: available to subclasses, not to callers.

Implementing a Custom Logger

To integrate Nanook with your own logging infrastructure, extend LoggerInterface and override the protected writeLog() method. It is called only for messages at or above level, with an entry { level, time, message }:

import { LoggerInterface } from '@xhubio/nanook-table'
import type { LogEntry } from '@xhubio/nanook-table'

interface WinstonLike {
  log(level: string, message: string): void
}

class WinstonLogger extends LoggerInterface {
  private winston: WinstonLike

  constructor(winston: WinstonLike) {
    super()
    this.winston = winston
  }

  protected override writeLog(level: string, entry: LogEntry): void {
    const message =
      typeof entry.message === 'string' ? entry.message : JSON.stringify(entry.message)
    this.winston.log(level, message)
  }
}

LoggerMemory

In-memory logger that stores log entries in arrays, organized by level. Optionally also writes to the console. This is the default logger used in examples and tests. Like every LoggerInterface, it stores only messages at or above level, which defaults to error.

Extends

LoggerInterface

Constructor

new LoggerMemory(options?: { writeConsole?: boolean })

Properties

Property Type Default Description
writeConsole boolean false When true, log entries are also printed to console. Set this to true during development to see output
entries Record<string, LogEntry[]> { debug: [], info: [], warning: [], error: [], fatal: [] } The stored log entries, organized by level

Methods

clear(): void

Empties all log entry arrays.

const logger = new LoggerMemory()
logger.level = 'info'
logger.info('hello')
console.log(logger.entries.info.length) // 1

logger.clear()
console.log(logger.entries.info.length) // 0

Example

import { LoggerMemory } from '@xhubio/nanook-table'

const logger = new LoggerMemory({ writeConsole: true })
logger.level = 'warning' // keep warnings too; the default keeps only error and fatal

logger.info('Starting generation')          // dropped: below 'warning'
logger.warning('Empty test case column found')

// Access stored entries
for (const entry of logger.entries.warning) {
  console.log(`Warning at ${entry.time}: ${JSON.stringify(entry.message)}`)
}

// Check for errors after processing
if (logger.entries.error.length > 0) {
  console.log(`${logger.entries.error.length} errors occurred`)
}

Log Entry Structure

Each entry in the entries arrays is a LogEntry:

Field Type Description
level string The level the entry was logged at
time string Formatted timestamp of when the entry was logged
message string | object The logged message or data object

getLoggerMemory(options?: { writeConsole?: boolean }): LoggerMemory

Returns a shared LoggerMemory instance: the first call creates it, every later call returns the same object (and ignores options). Nanook uses it where no logger is passed, for example in new FileProcessor() and createDefaultGeneratorRegistry(). For a logger of your own, use new LoggerMemory().

import { getLoggerMemory } from '@xhubio/nanook-table'

const logger = getLoggerMemory()
logger.writeConsole = true
logger.level = 'info'
logger.info('Ready')

Usage Patterns

Development -- console output enabled

const logger = new LoggerMemory()
logger.writeConsole = true
logger.level = 'debug'

Testing -- capture and assert on log entries

import { describe, it, expect } from 'vitest'
import { DataGeneratorRegistry, LoggerMemory } from '@xhubio/nanook-table'
import type { GeneratorDirectiveInterface } from '@xhubio/nanook-table'
import { MyGenerator } from '../src/MyGenerator.js' // your generator

describe('my generator', () => {
  it('logs an error for an unknown config', async () => {
    const logger = new LoggerMemory()
    const generatorRegistry = new DataGeneratorRegistry()
    const gen = new MyGenerator({ generatorRegistry, name: 'my', logger })

    // DataGeneratorBase logs a rejected doGenerate() and returns undefined
    const value = await gen.generate({
      instanceId: 'id1',
      generatorDirective: { config: 'unknown' } as GeneratorDirectiveInterface
    })

    expect(value).toBeUndefined()
    expect(logger.entries.error.length).toBe(1)
  })
})

Production -- suppress low-level output

const logger = new LoggerMemory()
logger.level = 'warning' // only warning, error, and fatal are logged