cenglu

Quick Reference

Quick reference guide for common cenglu operations

Quick Reference

Quick reference cheatsheet for common cenglu operations and patterns.

For detailed guides, see Installation, Basic Usage, and Configuration.

Installation

npm install cenglu

Basic Usage

import { createLogger } from "cenglu";

const logger = createLogger({ service: "my-app" });
logger.info("Hello, world!");

Log Levels

logger.trace("Trace level");   // 10 - Most verbose
logger.debug("Debug level");   // 20
logger.info("Info level");     // 30 - Default
logger.warn("Warning level");  // 40
logger.error("Error level");   // 50
logger.fatal("Fatal level");   // 60 - Most severe

Context & Bindings

// With context
logger.info("User action", { userId: 123, action: "login" });

// Child logger (permanent bindings)
const child = logger.child({ module: "users" });
child.info("Message"); // Includes module: "users"

// Bound logger (temporary bindings)
logger.with({ requestId: "abc" }).info("Message");

// Chain bindings
logger
  .with({ userId: 123 })
  .with({ sessionId: "xyz" })
  .info("Message");

See Context & Bindings for AsyncLocalStorage, correlation IDs, and automatic context propagation.

Error Logging

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

// Without error object
logger.error("Configuration invalid", { file: "config.json" });

Configuration

const logger = createLogger({
  // Basic
  level: "info",
  service: "my-app",
  env: "production",
  version: "1.0.0",

  // Bindings
  bindings: { region: "us-east-1" },

  // Pretty logs (development)
  pretty: {
    enabled: process.env.NODE_ENV !== "production",
  },

  // Structured output (production)
  structured: {
    type: "json", // json | ecs | datadog | splunk | logfmt
  },
  // See [Formatters](/docs/features/formatters) for format details

  // Security
  redaction: {
    enabled: true,
    paths: ["password", "apiKey"],
  },

  // Performance
  sampling: {
    rates: { trace: 0.1, debug: 0.5 },
  },
  // See [Sampling](/docs/features/sampling) for strategies and monitoring

  // Distributed tracing
  correlationId: () => crypto.randomUUID(),
});

Redaction

// Enable default redaction
const logger = createLogger({
  redaction: { enabled: true },
});

// Custom paths and patterns
redaction: {
  enabled: true,
  paths: ["password", "apiKey", "user.password"],
  patterns: [{ pattern: /Bearer\s+\S+/g, replacement: "Bearer [REDACTED]" }],
  customRedactor: (value, key) => {
    // Custom logic
    return undefined;
  },
}

See the Redaction Guide for default patterns, compliance presets (PCI/GDPR/HIPAA), and advanced usage.

Middleware

Express

import { expressMiddleware } from "cenglu";

app.use(expressMiddleware(logger, {
  ignorePaths: ["/health"],
  includeQuery: true,
  correlationIdHeader: "x-correlation-id",
}));

app.get("/users", (req, res) => {
  req.logger.info("Fetching users");
  res.json({ users: [] });
});

NestJS

import { nestjsMiddleware } from "cenglu";

app.use(nestjsMiddleware(logger, {
  ignorePaths: ["/health"],
}));

See middleware guides: Express, NestJS, Fastify, Koa

Plugins

import { samplingPlugin, rateLimitPlugin } from "cenglu";

const logger = createLogger({
  plugins: [
    samplingPlugin({ rates: { debug: 0.1 } }),
    rateLimitPlugin({ maxLogs: 1000, windowMs: 1000 }),
  ],
});

See Creating Plugins and Built-in Plugins for details.

Transports

See Console Transport, File Transport, and Custom Transports for detailed guides.

Console

import { createConsoleTransport } from "cenglu";

const logger = createLogger({
  transports: [
    createConsoleTransport({
      enabled: true,
      stream: process.stdout,
      errorStream: process.stderr,
    }),
  ],
});

File with Rotation

import { createRotatingFileTransport } from "cenglu";

const logger = createLogger({
  transports: [
    createRotatingFileTransport({
      enabled: true,
      dir: "./logs",
      separateErrors: true,
      rotation: {
        intervalDays: 1,
        maxBytes: 10485760, // 10MB
        maxFiles: 7,
        compress: "gzip",
        retentionDays: 30,
      },
    }),
  ],
});

Performance Timing

// Basic timer
const done = logger.time("operation");
await operation();
done(); // Logs duration

// Timer with context
const timer = logger.time("query", { table: "users" });
await query();
timer.endWithContext({ rowCount: 100 });

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

Level Management

// Change level at runtime
logger.setLevel("debug");

// Get current level
const level = logger.getLevel(); // "debug"

// Check if level is enabled
if (logger.isLevelEnabled("debug")) {
  logger.debug("Debug info", expensiveData());
}

// Conditional logging helpers
logger.ifDebug(() => {
  return ["Debug info", computeExpensiveData()];
});

Adapters

// Forward logs to external service
const logger = createLogger({
  adapters: [
    {
      name: "datadog",
      level: "info", // Only forward info and above
      handle: async (record) => {
        await datadogClient.log(record);
      },
    },
  ],
});

Custom Plugin

const myPlugin = {
  name: "my-plugin",
  order: 50,
  onRecord(record) { return { ...record, customField: "value" }; },
  onWrite(record, formatted) { /* side effects */ },
  async onFlush() { /* flush */ },
  async onClose() { /* cleanup */ },
};

const logger = createLogger({ plugins: [myPlugin] });

See Plugin System for hooks and lifecycle details.

Testing

import { createLogger } from "cenglu";

// Capture logs in tests
const logs: any[] = [];

const logger = createLogger({
  adapters: [
    {
      name: "test",
      handle: (record) => logs.push(record),
    },
  ],
});

// Run tests
logger.info("Test message", { data: 123 });

// Assert
expect(logs).toHaveLength(1);
expect(logs[0]).toMatchObject({
  level: "info",
  msg: "Test message",
  context: { data: 123 },
});

Graceful Shutdown

process.on("SIGTERM", async () => {
  console.log("Shutting down...");

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

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

  process.exit(0);
});

Common Patterns

Request Context

app.use((req, res, next) => {
  req.logger = logger.child({
    requestId: req.headers["x-request-id"] || uuid(),
    method: req.method,
    path: req.path,
  });
  next();
});

Structured Errors

try {
  await operation();
} catch (error) {
  logger.error("Operation failed", error, {
    operation: "create-user",
    userId: 123,
    attemptCount: 3,
  });
}

Async Context

import { LoggerContext, createRequestContext } from "cenglu";

app.use((req, res, next) => {
  const context = createRequestContext({
    id: uuid(),
    method: req.method,
    path: req.path,
  });

  LoggerContext.run(context, () => {
    next();
  });
});

// Logs automatically include context
logger.info("Processing request");

Environment Variables

# Log level
LOG_LEVEL=debug

# File transport
LOG_TO_FILE=true
LOG_DIR=./logs
LOG_ROTATE_DAYS=1
LOG_MAX_BYTES=10485760
LOG_MAX_FILES=7
LOG_COMPRESS=gzip
LOG_RETENTION_DAYS=30

# Service metadata
SERVICE_NAME=my-app
SERVICE_VERSION=1.0.0
NODE_ENV=production

Import Paths

// Core
import { createLogger } from "cenglu";

// Middleware
import { expressMiddleware } from "cenglu/middleware";
import { nestjsMiddleware } from "cenglu/middleware";

// Plugins
import { samplingPlugin } from "cenglu/plugins";

// Transports
import { createFileTransport } from "cenglu/transports";

// Redaction
import { createRedactor } from "cenglu/redaction";

// Context
import { LoggerContext } from "cenglu/context";

// Format
import { formatEcs } from "cenglu/format";

// Testing
import { createTestLogger } from "cenglu/testing";

Testing

import { createTestLogger } from "cenglu/testing";

// Create test logger with captured logs
const { logger, transport, time, random } = createTestLogger();

// Use in tests
logger.info("Test message", { userId: 123 });

// Assert logs
expect(transport.hasLog("info", "Test message")).toBe(true);
expect(transport.last()?.context?.userId).toBe(123);

// With custom matchers (after setup)
expect(transport).toHaveLogged("info", "Test message");
expect(transport).toHaveLoggedWithContext("userId", 123);

For detailed testing guide, see Testing Documentation.

On this page