cenglu

Logger API

Complete API reference for the Logger class

Logger API

createLogger()

Factory function to create a logger instance.

function createLogger(options?: LoggerOptions): Logger

Parameters

See Configuration for detailed options.

Returns

Returns a Logger instance.

Example

import { createLogger } from "cenglu";

const logger = createLogger({
  service: "my-app",
  level: "info",
});

Logger Class

Logging Methods

trace()

Log at trace level (most verbose).

logger.trace(message: string, context?: Bindings): void

Example:

logger.trace("Entering function", { functionName: "processData" });

debug()

Log at debug level.

logger.debug(message: string, context?: Bindings): void

Example:

logger.debug("Processing batch", { batchSize: 100, batchId: 42 });

info()

Log at info level.

logger.info(message: string, context?: Bindings): void

Example:

logger.info("User logged in", { userId: 123, ip: "192.168.1.1" });

warn()

Log at warn level.

logger.warn(message: string, context?: Bindings): void

Example:

logger.warn("Rate limit approaching", {
  current: 950,
  limit: 1000,
  userId: 123,
});

error()

Log at error level with optional error object.

logger.error(message: string, error?: Error, context?: Bindings): void
logger.error(message: string, context?: Bindings): void

Examples:

// With error object
try {
  await riskyOperation();
} catch (err) {
  logger.error("Operation failed", err, { attemptCount: 3 });
}

// Without error object
logger.error("Invalid configuration", { configFile: "app.json" });

fatal()

Log at fatal level (most severe).

logger.fatal(message: string, error?: Error, context?: Bindings): void
logger.fatal(message: string, context?: Bindings): void

Example:

logger.fatal("Database connection lost", error, {
  host: "db.example.com",
  attempts: 5,
});
process.exit(1);

Level Management

setLevel()

Change the minimum log level.

logger.setLevel(level: LogLevel): void

Example:

logger.setLevel("debug");
logger.debug("This will now be logged");

getLevel()

Get the current log level.

logger.getLevel(): LogLevel

Example:

const currentLevel = logger.getLevel();
console.log(`Current level: ${currentLevel}`); // "info"

isLevelEnabled()

Check if a log level is enabled.

logger.isLevelEnabled(level: LogLevel): boolean

Example:

if (logger.isLevelEnabled("debug")) {
  const expensiveData = computeExpensiveDebugData();
  logger.debug("Debug data", expensiveData);
}

Context Binding

with()

Create a lightweight bound logger with temporary context.

logger.with(context: Bindings): BoundLogger

Example:

const boundLogger = logger.with({ requestId: "abc-123" });
boundLogger.info("Processing request");

// Chain multiple with() calls
logger
  .with({ userId: 123 })
  .with({ action: "login" })
  .info("User action");

Returns: BoundLogger instance

child()

Create a child logger with permanent bindings.

logger.child(bindings: Bindings): Logger

Example:

const userLogger = logger.child({ module: "users" });
userLogger.info("User created", { userId: 123 });

// Nested child loggers
const requestLogger = userLogger.child({ requestId: "abc-123" });
requestLogger.info("Processing request");

Returns: New Logger instance that shares transports and configuration

Differences from with():

Featurewith()child()
ReturnsBoundLoggerLogger
BindingsTemporaryPermanent
PerformanceLighterHeavier
Use caseSingle-use contextLong-lived logger

Dynamic Logging

logAt()

Log at a dynamic level.

logger.logAt(level: LogLevel, message: string, context?: Bindings): void

Example:

function log(level: LogLevel, message: string) {
  logger.logAt(level, message, { timestamp: Date.now() });
}

log("info", "Application started");
log("error", "Application crashed");

Conditional Logging

Guard expensive operations with level checks.

ifTrace()

Execute function only if trace level is enabled.

logger.ifTrace(fn: () => [string, Bindings?]): void

ifDebug()

Execute function only if debug level is enabled.

logger.ifDebug(fn: () => [string, Bindings?]): void

ifInfo()

Execute function only if info level is enabled.

logger.ifInfo(fn: () => [string, Bindings?]): void

Example:

// Bad: Always computes expensive data
logger.debug("Debug data", computeExpensiveData());

// Good: Only computes if debug is enabled
logger.ifDebug(() => {
  const data = computeExpensiveData();
  return ["Debug data", data];
});

// With just message
logger.ifTrace(() => ["Trace message"]);

// With context
logger.ifInfo(() => ["Info message", { data: 123 }]);

Performance Timing

time()

Create a timer to measure operation duration.

logger.time(label: string, context?: Bindings): TimerResult

Returns: TimerResult object with methods:

  • () - End timer and log (same as .end())
  • .end() - End timer and log
  • .elapsed() - Get elapsed time without logging
  • .endWithContext(context) - End timer and log with additional context

Examples:

// Basic usage
const done = logger.time("database-query");
await db.query("SELECT * FROM users");
done(); // Logs: "database-query completed" { durationMs: 42 }

// End explicitly
const timer = logger.time("process-data");
await processData();
timer.end();

// Get elapsed without logging
const timer = logger.time("operation");
await operation();
const ms = timer.elapsed();
console.log(`Took ${ms}ms`);

// End with additional context
const timer = logger.time("api-request", {
  endpoint: "/users",
  method: "GET",
});
const response = await fetch("/users");
timer.endWithContext({
  statusCode: response.status,
  recordCount: response.data.length,
});

Timer Output:

{
  "level": "info",
  "msg": "database-query completed",
  "context": {
    "durationMs": 42
  }
}

Lifecycle Management

flush()

Flush all pending logs to transports.

logger.flush(): Promise<void>

Example:

// Before process exit
process.on("SIGTERM", async () => {
  await logger.flush();
  process.exit(0);
});

close()

Flush and close all transports and plugins.

logger.close(): Promise<void>

Example:

// Graceful shutdown
async function shutdown() {
  console.log("Shutting down...");

  // Flush pending logs
  await logger.flush();

  // Close transports and plugins
  await logger.close();

  process.exit(0);
}

process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);

Important: Only call close() on parent loggers, not child loggers.

const parent = createLogger({ service: "app" });
const child = parent.child({ module: "users" });

// On shutdown
await parent.close(); // ✅ Close parent
// await child.close(); // ❌ Never close child

BoundLogger Class

Created via logger.with() for temporary context bindings.

Methods

All logging methods are available with the same signature:

  • trace(message, context?)
  • debug(message, context?)
  • info(message, context?)
  • warn(message, context?)
  • error(message, error?, context?)
  • fatal(message, error?, context?)

Additional Methods

with()

Chain additional context.

boundLogger.with(context: Bindings): BoundLogger

Example:

const bound = logger
  .with({ userId: 123 })
  .with({ sessionId: "sess-abc" })
  .with({ action: "login" });

bound.info("User action");
// Includes all three contexts

child()

Create a child logger with merged context.

boundLogger.child(bindings: Bindings): Logger

Example:

const bound = logger.with({ requestId: "abc-123" });
const child = bound.child({ module: "users" });

child.info("User created");
// Includes both requestId and module

Type Definitions

LogLevel

type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";

Bindings

type Bindings = {
  [key: string]: unknown;
};

LogRecord

type LogRecord = {
  time: number;           // Unix timestamp (ms)
  level: LogLevel;        // Log severity
  msg: string;            // Log message
  context?: Bindings;     // Structured context
  err?: ErrorInfo | null; // Error details
  service?: string;       // Service name
  env?: string;           // Environment
  version?: string;       // Version
  traceId?: string;       // Distributed trace ID
  spanId?: string;        // Span ID
};

ErrorInfo

type ErrorInfo = {
  name?: string;
  message?: string;
  stack?: string;
  code?: string | number;
  cause?: ErrorInfo;
  [key: string]: unknown;
};

TimerResult

type TimerResult = {
  (): void;                               // End timer and log
  end(): void;                            // End timer and log
  elapsed(): number;                      // Get elapsed ms
  endWithContext(context: Bindings): void; // End with context
};

Constants

Log Levels

import { LEVELS, LEVEL_VALUES } from "cenglu";

console.log(LEVELS);
// ["trace", "debug", "info", "warn", "error", "fatal"]

console.log(LEVEL_VALUES);
// { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60 }

Default Theme

import { DEFAULT_THEME, NO_COLOR_THEME } from "cenglu";

const logger = createLogger({
  pretty: {
    enabled: true,
    theme: DEFAULT_THEME, // Colored theme
  },
});

const noColorLogger = createLogger({
  pretty: {
    enabled: true,
    theme: NO_COLOR_THEME, // No colors
  },
});

Utility Functions

isValidLevel()

Check if a string is a valid log level.

import { isValidLevel } from "cenglu";

console.log(isValidLevel("info"));  // true
console.log(isValidLevel("debug")); // true
console.log(isValidLevel("invalid")); // false

On this page