Semola

Logging

Prefixed loggers with console and file providers

Structured-enough logging without pulling in a framework. One logger, one or more providers, optional formatters.

Import

import {
  Logger,
  LogLevel,
  ConsoleProvider,
  FileProvider,
  JSONFormatter,
} from "semola/logging";

Quick start

One Logger sends five severity levels to the console, prefixing every line with api.

const log = new Logger("api", [new ConsoleProvider()]);

log.debug("handshake");
log.info("server started");
log.warning("slow query");
log.error("request failed");
log.critical("cannot reach database");

The first argument is a prefix shown on every line.

Providers

Pass several providers to fan out:

Each log call writes the same formatted entry to both the console and file. FileProvider treats the path as a template and inserts a counter before the extension (./logs/worker.log becomes ./logs/worker.0.log; rotation writes worker.1.log, and so on).

const log = new Logger("worker", [
  new ConsoleProvider(),
  new FileProvider("./logs/worker.log"),
]);

Levels and formatters

LogLevel enumerates severity. Providers accept a minimum level (default "debug") and a formatter (default BaseFormatter).

JSONFormatter emits JSON lines. Date helpers (isoDateFormat, isoDateTimeFormat, dmyFormat, mdyFormat) help with timestamps.

FileProvider accepts a path and optional rotation policy (size-based by default, or time-based). A .json path writes simple JSON lines.

Examples

Console and file providers

Info-and-higher entries go to the console, while the file provider writes and rotates api.0.log.

const log = new Logger("api", [
  new ConsoleProvider({ level: "info" }),
  new FileProvider("./logs/api.log", {
    policy: { type: "size" },
  }),
]);

log.info("listening");

JSON formatter

The provider formats each entry as one JSON object per line.

const log = new Logger("jobs", [
  new ConsoleProvider({
    formatter: new JSONFormatter(),
  }),
]);

log.warning("retry scheduled");

Filter noise

The warning threshold drops the debug entry and emits the warning.

const log = new Logger("http", [
  new ConsoleProvider({ level: "warning" }),
]);

log.debug("ignored");
log.warning("slow request");

Date formatter helpers

Date helpers return timestamp strings and can be passed directly to a formatter.

const formatter = new BaseFormatter(isoDateTimeFormat);

const log = new Logger("api", [
  new ConsoleProvider({ formatter }),
]);

Custom logger

Extending AbstractLogger lets a specialized logger define its own severity behavior.

class SilentLogger extends AbstractLogger {
  public debug() {}
  public info() {}
  public warning() {}
  public error() {}
  public critical() {}
}

const log = new SilentLogger("app", [new ConsoleProvider()]);
log.info("ready");

Custom provider

Extending LoggerProvider creates a new sink. execute() receives each routed entry, and getLogLevel() exposes its configured threshold.

class MemoryProvider extends LoggerProvider {
  public entries: LogDataType[] = [];

  public execute(data: LogDataType) {
    this.entries.push(data);
  }
}

Reference

Logger

CallMeaning
new Logger(prefix, providers)Create a logger
debug / info / warning / error / criticalLog at that level

Providers

ExportMeaning
ConsoleProviderWrite to the console
FileProviderWrite to a file (optional rotation). The path is a template: api.log becomes api.0.log
JSONFormatter / BaseFormatterFormat log lines

Extend AbstractLogger or LoggerProvider if you need a custom sink. Most apps only need Logger + ConsoleProvider.

On this page