# Logging cookbook Recipes and patterns for common logging tasks with `@administratrix/esm-logging`. ## Using logging across multiple modules `getLogger` returns the same logger instance for a given scope name across your entire application. Configure handlers on a parent logger and create child loggers in each module: ```javascript // main.js import * as logging from '@administratrix/esm-logging'; import { ConsoleHandler } from '@administratrix/esm-logging/src/handler'; import { Formatter } from '@administratrix/esm-logging/src/formatter'; import { doWork } from './worker.js'; const logger = logging.manager.MANAGER.getLogger('myapp'); logger.setLevel(logging.log_level.DEBUG); const handler = new ConsoleHandler(); handler.level = logging.log_level.DEBUG; handler.formatter = new Formatter({ fmt: '%(asctime)s - %(name)s - %(levelname)s - %(message)s', }); logger.addHandler(handler); logger.info('Application starting'); doWork(); logger.info('Application finished'); ``` ```javascript // worker.js import * as logging from '@administratrix/esm-logging'; const logger = logging.manager.MANAGER.getLogger('myapp.worker'); export function doWork() { logger.debug('Starting work'); // ... do something ... logger.info('Work completed'); } ``` Because `myapp.worker` is a child of `myapp`, its records propagate up to the handler configured on `myapp`. No handler configuration is needed in `worker.js`. Output: ``` 2026-03-14 10:00:00.000 - myapp - INFO - Application starting 2026-03-14 10:00:00.001 - myapp.worker - DEBUG - Starting work 2026-03-14 10:00:00.002 - myapp.worker - INFO - Work completed 2026-03-14 10:00:00.003 - myapp - INFO - Application finished ``` ## Logging to multiple destinations Attach multiple handlers to a single logger, each with its own level and formatter: ```javascript import * as logging from '@administratrix/esm-logging'; import { ConsoleHandler, StderrHandler } from '@administratrix/esm-logging/src/handler'; import { Formatter } from '@administratrix/esm-logging/src/formatter'; const logger = logging.manager.MANAGER.getLogger('myapp'); logger.setLevel(logging.log_level.DEBUG); // console handler: shows everything with detailed format const consoleHandler = new ConsoleHandler(); consoleHandler.level = logging.log_level.DEBUG; consoleHandler.formatter = new Formatter({ fmt: '%(asctime)s [%(levelname)s] %(name)s: %(message)s', }); logger.addHandler(consoleHandler); // stderr handler: only errors, compact format const errorHandler = new StderrHandler(logging.log_level.ERROR); errorHandler.formatter = new Formatter({ fmt: 'ERROR %(asctime)s %(name)s: %(message)s', datefmt: '%Y-%m-%d %H:%M:%S', }); logger.addHandler(errorHandler); ``` ## Using basicConfig for simple scripts For quick scripts, `basicConfig` sets up a handler on the root logger: ```javascript import * as logging from '@administratrix/esm-logging'; logging.config.basicConfig({ level: logging.log_level.INFO, format: '%(levelname)s: %(message)s', }); const logger = logging.manager.MANAGER.getLogger('script'); logger.info('Running'); logger.warning('Check this'); ``` Output: ``` INFO: Running WARNING: Check this ``` ## Filtering records ### By scope Only allow records from a specific part of the hierarchy: ```javascript import { Filter } from '@administratrix/esm-logging/src/filter'; const dbFilter = new Filter('myapp.db'); handler.addFilter(dbFilter); // handler now only processes records from 'myapp.db' and its children ``` ### By custom criteria Use any object with a `filter(record)` method: ```javascript handler.addFilter({ filter(record) { // only pass records that contain 'important' in the message return record.msg.includes('important'); } }); ``` ## Custom formatters Create formatters with different format strings for different contexts: ```javascript import { Formatter } from '@administratrix/esm-logging/src/formatter'; // detailed format for development const devFormatter = new Formatter({ fmt: '%(asctime)s %(levelname)s %(name)s: %(message)s', datefmt: '%H:%M:%S', }); // compact format for production const prodFormatter = new Formatter({ fmt: '%(levelname)s:%(name)s:%(message)s', }); ``` ## Custom handlers Subclass `Handler` and implement `emit(record)`: ```javascript import { Handler } from '@administratrix/esm-logging/src/handler'; class BufferHandler extends Handler { constructor(level) { super(level); this.buffer = []; } emit(record) { try { this.buffer.push(this.format(record)); if (this.buffer.length >= 100) { this.flush(); } } catch (e) { this.handleError(record); } } flush() { // send buffered records somewhere const batch = this.buffer.splice(0); // ... process batch ... } } ``` ## Disabling logging below a threshold The manager's `disable` property suppresses all logging at or below a given level across all loggers: ```javascript import * as logging from '@administratrix/esm-logging'; // suppress DEBUG and INFO globally logging.manager.MANAGER.disable = logging.log_level.INFO; ``` ## Reconfiguring with force `basicConfig` only takes effect once. To reconfigure, use `force: true`: ```javascript logging.config.basicConfig({ level: logging.log_level.DEBUG, format: '%(asctime)s %(message)s', force: true, }); ``` This removes and closes all existing handlers on the root logger before applying the new configuration.