### Example log output Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx This is an example of the JSON output you should see after a successful installation and logging. ```json {"time":1704067200000,"level":"info","msg":"Cenglu installed successfully!","context":{"version":"2.2.0"},"service":"test-app"} ``` -------------------------------- ### Run Development Server Source: https://github.com/ayungavis/cenglu/blob/main/docs/README.md Use these commands to start the development server for the project. Ensure you have npm, pnpm, or yarn installed. ```bash npm run dev ``` ```bash pnpm dev ``` ```bash yarn dev ``` -------------------------------- ### Quick Start: Testing UserService Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/testing.mdx A quick example demonstrating how to use `createTestLogger` to test a `UserService` that utilizes the Cenglu logger. ```APIDOC ## Quick Start: Testing UserService ### Description This example shows how to set up a test environment using `createTestLogger` to test a `UserService`. It captures logs generated by the service and uses assertions to verify logging behavior. ### Method N/A (Illustrative Example) ### Endpoint N/A ### Request Example ```typescript import { describe, it, expect, beforeEach } from "vitest"; import { createTestLogger } from "cenglu/testing"; import { UserService } from "./user-service"; describe("UserService", () => { let logger, transport; beforeEach(() => { ({ logger, transport } = createTestLogger()); }); it("logs user creation", async () => { const service = new UserService(logger); await service.createUser({ email: "test@example.com" }); expect(transport.hasLog("info", "User created")).toBe(true); expect(transport.last()?.context?.email).toBe("test@example.com"); }); }); ``` ### Response N/A (Illustrative Example) ``` -------------------------------- ### Complete Koa Application Setup with Cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/koa.mdx This example shows a full Koa application setup including error handling, body parsing, request/response logging, health checks, user routes, graceful shutdown, and server startup. ```typescript import Koa from "koa"; import Router from "@koa/router"; import bodyParser from "koa-bodyparser"; import { createLogger, koaMiddleware, koaErrorMiddleware } from "cenglu"; const logger = createLogger({ service: "user-api", env: process.env.NODE_ENV, level: "info", redaction: { enabled: true }, }); const app = new Koa(); const router = new Router(); // Error middleware (first) app.use(koaErrorMiddleware(logger, { exposeErrors: process.env.NODE_ENV !== "production", })); // Body parser app.use(bodyParser()); // Logging middleware app.use(koaMiddleware(logger, { logRequests: true, logResponses: true, includeQuery: true, ignorePaths: ["/health", "/metrics"], })); // Health check router.get("/health", (ctx) => { ctx.body = { status: "ok" }; }); // Routes router.get("/users/:id", async (ctx) => { const timer = ctx.logger.time("fetch-user"); try { const user = await fetchUser(ctx.params.id); timer.endWithContext({ userId: user.id }); ctx.logger.info("User fetched successfully", { userId: user.id }); ctx.body = user; } catch (error) { ctx.logger.error("Failed to fetch user", error, { userId: ctx.params.id, }); ctx.status = 404; ctx.body = { error: "User not found" }; } }); router.post("/users", async (ctx) => { const body = ctx.request.body as { email: string; name: string }; ctx.logger.info("Creating user", { email: body.email }); try { const user = await createUser(body); ctx.logger.info("User created", { userId: user.id }); ctx.status = 201; ctx.body = user; } catch (error) { ctx.logger.error("Failed to create user", error); ctx.status = 500; ctx.body = { error: "Failed to create user" }; } }); // Register routes app.use(router.routes()); app.use(router.allowedMethods()); // Error event handler app.on("error", (err, ctx) => { logger.error("Application error", err, { path: ctx.path, method: ctx.method, }); }); // Graceful shutdown const closeGracefully = async (signal: string) => { logger.info(`Received ${signal}, shutting down gracefully`); // Close server server.close(async () => { await logger.flush(); await logger.close(); logger.info("Application stopped"); process.exit(0); }); // Force exit after timeout setTimeout(() => { logger.error("Forced shutdown after timeout"); process.exit(1); }, 10000); }; process.on("SIGTERM", () => closeGracefully("SIGTERM")); process.on("SIGINT", () => closeGracefully("SIGINT")); // Start server const server = app.listen(3000, () => { logger.info("Server started", { port: 3000, nodeVersion: process.version, }); }); // Handle startup errors server.on("error", (error) => { logger.fatal("Failed to start server", error); process.exit(1); }); ``` -------------------------------- ### onInit Hook Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/plugin-system.mdx Demonstrates the 'onInit' hook, which is called once when the logger is created. Use this for setup tasks like initializing connections or validating configuration. ```typescript { name: "my-plugin", onInit(logger: Logger) { console.log("Plugin initialized!"); // Setup resources, validate config, etc. } } ``` -------------------------------- ### Run Plugin Example Source: https://github.com/ayungavis/cenglu/blob/main/README.md Execute the plugin example using ts-node to demonstrate batching and HTTP sinks. This example shows plugin usage patterns and graceful shutdown. ```bash # Run directly with ts-node (recommended for quick demo) npx ts-node examples/plugin-example.ts # Or compile and run npx tsc examples/plugin-example.ts --esModuleInterop --module es2022 --target es2022 node examples/plugin-example.js ``` -------------------------------- ### Import Examples Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx Examples of how to import various types from the Cenglu library. ```APIDOC ## Import Examples ```typescript // Core types import type { Logger, LogLevel, LogRecord, Bindings, ErrorInfo, } from "cenglu"; // Configuration types import type { LoggerOptions, ConsoleOptions, FileOptions, PrettyOptions, StructuredFormat, SamplingOptions, RedactionOptions, } from "cenglu"; // Extension types import type { Transport, AsyncTransport, LoggerPlugin, ProviderAdapter, } from "cenglu"; // State types import type { LoggerState, LoggerConfig, TimerResult, } from "cenglu"; // Utility types import type { TraceContext, Theme, TreeOptions, FormatterType, } from "cenglu"; ``` ``` -------------------------------- ### Installing Dependencies and Running Tests Source: https://github.com/ayungavis/cenglu/blob/main/README.md Install project dependencies using Bun and run the test suite. ```bash cd cenglu bun install bun run test ``` -------------------------------- ### Vitest Test Structure Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Set up tests using Vitest. This example demonstrates importing necessary testing utilities, defining a test suite, using beforeEach and afterEach hooks for setup and cleanup, and writing a basic test case with assertions. ```typescript import { describe, expect, it, beforeEach, afterEach } from "vitest"; import { createTestLogger } from "../src/testing"; describe("Feature", () => { let logger, transport, reset; beforeEach(() => { ({ logger, transport, reset } = createTestLogger()); }); afterEach(() => { reset(); // Clean up between tests }); it("should do something", () => { // Arrange & Act logger.info("test", { key: "value" }); // Assert expect(transport.hasLog("info", "test")).toBe(true); expect(transport.last()?.context?.key).toBe("value"); }); }); ``` -------------------------------- ### File Transport Setup with Pino Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-pino.mdx Configure Pino to write logs to a file. Ensure the 'pino' and 'pino/file' modules are installed. ```typescript import pino from "pino"; import { createWriteStream } from "pino/file"; const logger = pino(createWriteStream("./logs/app.log")); ``` -------------------------------- ### Install project dependencies Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Install project dependencies using either Bun or npm. ```bash bun install # or npm install ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/ayungavis/cenglu/blob/main/examples/nestjs/README.md Installs all necessary project dependencies using pnpm. Ensure you have pnpm installed globally. ```bash pnpm install ``` -------------------------------- ### Install cenglu with bun Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx Use this command to install cenglu using bun. ```bash bun add cenglu ``` -------------------------------- ### Install Project Dependencies with Bun Source: https://github.com/ayungavis/cenglu/blob/main/examples/express/README.md Use this command to install all necessary project dependencies when using Bun. ```bash bun install ``` -------------------------------- ### ConsoleOptions Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example configuration for the console transport, specifying standard output and error streams. ```json { "enabled": true, "stream": process.stdout, "errorStream": process.stderr, } ``` -------------------------------- ### Install Cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/examples/nestjs-integration.mdx Install the cenglu package using npm. ```bash npm install cenglu ``` -------------------------------- ### LogRecord Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example illustrating the structure of a LogRecord object with typical values. ```json { "time": 1700000000000, "level": "info", "msg": "User created", "context": { "userId": 123, "email": "user@example.com" }, "service": "user-service", "env": "production", "version": "1.2.3", "traceId": "abc-123" } ``` -------------------------------- ### Install cenglu with pnpm Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx Use this command to install cenglu using pnpm. ```bash pnpm add cenglu ``` -------------------------------- ### Run development build Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Start a development build with watch mode enabled. ```bash bun run dev ``` -------------------------------- ### Example File Rotation Configuration Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example configuration for file rotation, setting rotation every day, a maximum file size of 10MB, keeping 7 rotated files, using gzip compression, and retaining files for 30 days. ```typescript { intervalDays: 1, maxBytes: 10 * 1024 * 1024, // 10MB maxFiles: 7, compress: "gzip", retentionDays: 30, } ``` -------------------------------- ### Install cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/quick-reference.mdx Install the cenglu package using a package manager. ```bash cenglu ``` -------------------------------- ### Install cenglu with yarn Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx Use this command to install cenglu using yarn. ```bash yarn add cenglu ``` -------------------------------- ### Verify Gzip Installation Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/transports/file.mdx Confirm that the `gzip` utility is installed and accessible in the system's PATH, which is required for log compression. ```bash which gzip ``` -------------------------------- ### Usage Example for logger.time() Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx Demonstrates how to use logger.time() to measure operation duration and log it, with options to get elapsed time or add context. ```typescript const done = logger.time("operation", { taskId: 123 }); // ... do work ... done(); // Logs with duration ``` ```typescript const timer = logger.time("query"); const ms = timer.elapsed(); // Get elapsed time timer.endWithContext({ rows: 10 }); // End with context ``` -------------------------------- ### Install Fastify and Cenglu Plugin Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/fastify.mdx Import necessary modules from Fastify and cenglu for plugin integration. ```typescript import Fastify from "fastify"; import { createLogger, fastifyPlugin } from "cenglu"; ``` -------------------------------- ### Advanced Patterns: Testing Source: https://github.com/ayungavis/cenglu/blob/main/README.md Example of how to set up a logger for testing purposes by providing a custom adapter that captures log records. ```APIDOC ## Advanced Patterns: Testing ### Example ```typescript const logs = []; const logger = createLogger({ adapters: [ { name: "test", handle: (record) => logs.push(record), }, ], }); expect(logs).toContainEqual(expect.objectContaining({ level: "error", msg: "payment failed" })); ``` ``` -------------------------------- ### Run the test logger file Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx Execute the test logger file using Node.js or Bun to verify the installation. ```bash node test-logger.ts ``` ```bash bun test-logger.ts ``` -------------------------------- ### Check bundle size with size-limit Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/installation.mdx Install the size-limit globally and run it in your project to check the bundle size of cenglu. ```bash npm install -g size-limit size-limit ``` -------------------------------- ### Install and Deploy with Mau Source: https://github.com/ayungavis/cenglu/blob/main/examples/nestjs/README.md Installs the NestJS Mau CLI globally and deploys your application to AWS. Requires AWS credentials to be configured. ```bash pnpm install -g @nestjs/mau mau deploy ``` -------------------------------- ### Plugin Execution Order Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/data-flow.mdx Illustrates how plugins are executed in a specific order based on their `order` property (ascending). This example shows sampling, redaction, enrichment, and metrics plugins. ```typescript const logger = createLogger({ plugins: [ samplingPlugin({ order: 10 }), // 1. Drop 90% of debug logs redactionPlugin({ order: 20 }), // 2. Redact sensitive data enrichPlugin({ order: 30 }), // 3. Add hostname, PID metricsPlugin({ order: 40 }), // 4. Count logs by level ], }); ``` -------------------------------- ### Example Log Sampling Configuration Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example sampling configuration that sets a default 10% sampling rate, always logs errors, samples 50% of warnings, and samples 1% of debug logs. ```typescript { defaultRate: 0.1, rates: { error: 1.0, warn: 0.5, debug: 0.01, } } ``` -------------------------------- ### Example LogRecord Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx An example of a structured LogRecord, including timestamp, level, message, context, and tracing information. ```json { "time": 1700000000000, "level": "info", "msg": "User created successfully", "context": { "userId": 12345, "email": "user@example.com", "requestId": "abc-123", "duration": 42, }, "service": "user-service", "env": "production", "version": "1.2.3", "traceId": "abc-123-def-456", "spanId": "span-789", } ``` -------------------------------- ### ErrorInfo with Cause Chain Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example demonstrating the ErrorInfo structure with a nested error cause chain. ```json { "name": "ApiError", "message": "Failed to fetch user", "code": "API_ERROR", "cause": { "name": "NetworkError", "message": "Connection timeout", "code": "ETIMEDOUT" } } ``` -------------------------------- ### Pino Pretty Printing Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-pino.mdx Configure pretty printing for Pino logs using the 'pino-pretty' package. ```typescript import pino from "pino"; import pretty from "pino-pretty"; const logger = pino(pretty({ colorize: true, translateTime: "SYS:standard", })); ``` -------------------------------- ### Configure Plugin Execution Order Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Example configuration showing how to define the order of plugin execution. Lower 'order' values are executed earlier. ```typescript plugins: [ { name: "sampling", order: 10 }, // Runs 1st - drop unwanted logs { name: "redaction", order: 20 }, // Runs 2nd - remove sensitive data { name: "enrich", order: 50 }, // Runs 3rd - add context { name: "metrics", order: 80 }, // Runs 4th - count logs { name: "batch", order: 100 }, // Runs 5th (default) - buffer & send ] ``` -------------------------------- ### Setup Cenglu Custom Matchers for Vitest/Jest Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/testing.mdx Shows how to set up Cenglu's custom matchers globally in a test setup file or individually in test files. ```typescript // In your test setup file (e.g., vitest.setup.ts) import { expect } from "vitest"; import { setupLoggerMatchers } from "cenglu/testing"; setupLoggerMatchers(expect); // Or in individual test files beforeAll(() => { setupLoggerMatchers(expect); }); ``` -------------------------------- ### Express Basic Middleware Setup Source: https://context7.com/ayungavis/cenglu/llms.txt Integrate basic Express middleware for automatic request logging and correlation ID propagation. This setup provides a foundation for request-aware logging. ```typescript import express from "express"; import { createLogger, expressMiddleware, expressErrorMiddleware } from "cenglu"; const app = express(); const logger = createLogger({ service: "api" }); // Basic middleware setup app.use(expressMiddleware(logger)); ``` -------------------------------- ### Plugin Composition Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/built-in-plugins.mdx Combine multiple Cenglu plugins to create a sophisticated logging pipeline. The 'order' property determines the execution sequence. ```typescript const logger = createLogger({ plugins: [ // Order matters! Lower order runs first samplingPlugin({ rates: { debug: 0.1 }, order: 5 }), rateLimitPlugin({ maxLogs: 1000, order: 10 }), redactionPlugin({ enabled: true, order: 15 }), enrichPlugin({ addProcessInfo: true, order: 20 }), filterPlugin({ minLevel: "info", order: 25 }), batchingPlugin({ maxBatchSize: 100, onBatch: sendLogs, order: 30 }), metricsPlugin({ collector: createConsoleMetricsCollector(), flushInterval: 60000, order: 100 }), ], }); ``` -------------------------------- ### Cenglu Pretty Printing Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-pino.mdx Enable built-in pretty printing for Cenglu logs. No external dependency is required. ```typescript import { createLogger } from "cenglu"; const logger = createLogger({ pretty: { enabled: true, // Built-in, no external dependency }, }); ``` -------------------------------- ### Install Koa and Cenglu Middleware Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/koa.mdx Import necessary modules from Koa and cenglu for middleware integration. ```typescript import Koa from "koa"; import { createLogger, koaMiddleware } from "cenglu"; ``` -------------------------------- ### Create Winston Logger Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of creating a logger instance using Winston with console and file transports. ```typescript import winston from "winston"; const logger = winston.createLogger({ level: "info", format: winston.format.json(), defaultMeta: { service: "my-app" }, transports: [ new winston.transports.Console(), new winston.transports.File({ filename: "app.log" }), ], }); ``` -------------------------------- ### Serverless Function Logging Setup with Cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Configure Cenglu for a serverless function (e.g., AWS Lambda) with CloudWatch-friendly JSON output and minimal setup for optimization. Includes enrichment plugin for request-specific details. ```typescript const logger = createLogger({ service: "lambda-function", level: "info", // CloudWatch-friendly format structured: { type: "json" }, // Minimal setup (Lambda handles output) console: { enabled: true }, file: { enabled: false }, // Fast logging (cold start optimization) plugins: [ enrichPlugin({ fields: { requestId: process.env.AWS_REQUEST_ID, functionName: process.env.AWS_LAMBDA_FUNCTION_NAME, }, }), ], }); export const handler = async (event: APIGatewayEvent) => { logger.info("Processing request", { path: event.path }); // ... handle request }; ``` -------------------------------- ### Examples of Max Size Parsing Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/transports/file.mdx Illustrates various ways to specify the `maxSize` option, including bytes, kilobytes, megabytes, and gigabytes, with and without units. ```typescript maxSize: 1024 // 1024 bytes maxSize: "1024" // 1024 bytes maxSize: "1k" // 1024 bytes maxSize: "1.5m" // 1.5 megabytes maxSize: "10mb" // 10 megabytes maxSize: "1gb" // 1 gigabyte ``` -------------------------------- ### Time an Operation with Initial Context Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/basic-usage.mdx Start a timer with initial context that will be included in the final log entry. This is useful for logging details about the operation's setup. ```typescript const done = logger.time("api-request", { endpoint: "/users", method: "GET" }); await fetch("https://api.example.com/users"); done.endWithContext({ statusCode: 200, recordCount: 50 }); ``` -------------------------------- ### Jest Configuration for Cenglu Testing Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/testing.mdx Configure Jest to use a setup file for integrating Cenglu's testing matchers. ```javascript // jest.config.js module.exports = { setupFilesAfterEnv: ["./jest.setup.ts"], }; // jest.setup.ts import { setupLoggerMatchers } from "cenglu/testing"; setupLoggerMatchers(expect); ``` -------------------------------- ### Plugin with Initialization and Cleanup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/creating-plugins.mdx Demonstrates using onInit for setup tasks like establishing a connection and onClose for cleanup. The plugin accesses logger properties during initialization. ```typescript const setupPlugin: LoggerPlugin = { name: "setup", onInit(logger: Logger) { console.log("Plugin initialized"); // Access logger properties console.log("Logger level:", logger.getLevel()); // Perform setup this.connection = setupConnection(); }, // Clean up in onClose async onClose() { await this.connection?.close(); }, }; ``` -------------------------------- ### Create Logger with Default Console Transport Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/transports/console.mdx Quick start example for creating a logger that uses the default console transport. Logs are automatically written to stdout and stderr based on their level. ```typescript import { createLogger } from "cenglu"; const logger = createLogger({ service: "my-app", }); logger.info("Hello, world!"); // Writes to stdout logger.error("Something failed"); // Writes to stderr ``` -------------------------------- ### Documentation Directory Structure Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Overview of the project's documentation directory structure. It shows the organization of MDX files for different sections like index, getting started, and API documentation. ```directory docs/ ├── index.mdx ├── getting-started/ │ ├── installation.mdx │ └── basic-usage.mdx └── api/ └── logger.mdx ``` -------------------------------- ### Quick Start: Testing User Service with Cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/testing.mdx Demonstrates setting up a test logger and asserting log messages for user creation. Requires Vitest for testing framework. ```typescript import { describe, it, expect, beforeEach } from "vitest"; import { createTestLogger } from "cenglu/testing"; import { UserService } from "./user-service"; describe("UserService", () => { let logger, transport; beforeEach(() => { ({ logger, transport } = createTestLogger()); }); it("logs user creation", async () => { const service = new UserService(logger); await service.createUser({ email: "test@example.com" }); expect(transport.hasLog("info", "User created")).toBe(true); expect(transport.last()?.context?.email).toBe("test@example.com"); }); }); ``` -------------------------------- ### Run production build Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Generate a production-ready build of the project. ```bash bun run build ``` -------------------------------- ### Complete Express.js Application with Cenglu Logging Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/express.mdx This snippet shows a full Express.js server setup using Cenglu for logging. It includes middleware for request and error logging, route handlers, and graceful shutdown. Ensure body-parser is installed for includeBody functionality. ```typescript import express from "express"; import bodyParser from "body-parser"; import { createLogger, expressMiddleware, expressErrorMiddleware } from "cenglu"; const app = express(); const logger = createLogger({ service: "user-api", env: process.env.NODE_ENV, level: "info", redaction: { enabled: true }, }); // Body parser (required for includeBody) app.use(bodyParser.json()); // Logging middleware app.use(expressMiddleware(logger, { logRequests: true, logResponses: true, includeQuery: true, ignorePaths: ["/health", "/metrics"], getRequestContext: (req) => ({ userId: req.user?.id, tenantId: req.headers["x-tenant-id"], }), })); // Routes app.get("/health", (req, res) => { res.json({ status: "ok" }); }); app.get("/users/:id", async (req, res) => { const timer = req.logger.time("fetch-user"); try { const user = await fetchUser(req.params.id); timer.endWithContext({ userId: user.id }); req.logger.info("User fetched successfully", { userId: user.id }); res.json(user); } catch (error) { req.logger.error("Failed to fetch user", error, { userId: req.params.id, }); res.status(404).json({ error: "User not found" }); } }); app.post("/users", async (req, res) => { req.logger.info("Creating user", { email: req.body.email }); try { const user = await createUser(req.body); req.logger.info("User created", { userId: user.id }); res.status(201).json(user); } catch (error) { req.logger.error("Failed to create user", error); res.status(500).json({ error: "Failed to create user" }); } }); // Error middleware (last) app.use(expressErrorMiddleware(logger)); // Graceful shutdown process.on("SIGTERM", async () => { console.log("Shutting down..."); await logger.flush(); await logger.close(); process.exit(0); }); app.listen(3000, () => { logger.info("Server started", { port: 3000 }); }); ``` -------------------------------- ### Basic Batching Plugin Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/built-in-plugins.mdx Set up the batching plugin to group logs before sending them. Configure `batchSize`, `flushInterval`, and an `onFlush` callback to handle the batched records. ```typescript import { createLogger, batchingPlugin } from "cenglu"; const logger = createLogger({ plugins: [ batchingPlugin({ batchSize: 100, // Max records per batch flushInterval: 5000, // Flush every 5 seconds onFlush: async (records) => { // Send batch to external service await sendToDatadog(records); }, }), ], }); ``` -------------------------------- ### Winston Format Combiner Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of combining timestamp and JSON formats in Winston. ```typescript winston.format.combine( winston.format.timestamp(), winston.format.json() ) ``` -------------------------------- ### Conventional Commit example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/contributing.mdx Examples of commit messages following the Conventional Commits specification. ```bash git commit -m "feat(middleware): add Fastify middleware" git commit -m "fix(logger): handle null context values" git commit -m "docs: update installation guide" git commit -m "test(redaction): add PCI compliance tests" ``` -------------------------------- ### Logger Initialization with Plugins Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/data-flow.mdx Sets up a logger instance with specific service and environment configurations, including custom plugins for sampling, enrichment, and redaction. ```typescript // 1. Setup const logger = createLogger({ service: "user-service", env: "production", level: "info", bindings: { version: "1.2.3" }, plugins: [ samplingPlugin({ defaultRate: 1.0, rates: { debug: 0.1 } }), enrichPlugin({ fields: { hostname: os.hostname() } }), ], redaction: { enabled: true }, }); ``` -------------------------------- ### Initialize Test Logger with Options Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/development/testing.mdx Sets up a test logger with custom start time, random values, and log level. Ensure `samplingPlugin` is imported if used. ```typescript import { createTestLogger } from "cenglu/testing"; const { logger, transport, time, random, reset } = createTestLogger({ startTime: 1700000000000, // Initial timestamp randomValues: [0.1, 0.5, 0.9], // Sequence of random values debug: false, // Set to true to see logs in console // Any other LoggerOptions... level: "info", plugins: [samplingPlugin({ defaultRate: 0.5 })], }); // Use logger in your tests logger.info("Test message", { userId: 123 }); // Make assertions expect(transport.logs).toHaveLength(1); expect(transport.last()?.msg).toBe("Test message"); // Clean up after test reset(); ``` -------------------------------- ### Cenglu Structured Format Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of configuring Cenglu for JSON output using the structured option. ```typescript { structured: { type: "json" } } ``` -------------------------------- ### Basic Metrics Plugin Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/built-in-plugins.mdx Integrate the metrics plugin to track logging statistics. It requires a metrics collector and can be configured with a prefix, tags, and intervals. ```typescript import { createLogger, metricsPlugin, createConsoleMetricsCollector } from "cenglu"; const logger = createLogger({ plugins: [ metricsPlugin({ collector: createConsoleMetricsCollector(), flushInterval: 60000, // Flush every minute prefix: "myapp.logs", tags: { service: "api", env: "production" }, trackLevels: true, trackErrorTypes: true, }), ], }); ``` -------------------------------- ### Example Error Log Output Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/express.mdx An example of the JSON output generated by the error middleware, including correlation ID, error details, and request context. ```json { "level": "error", "msg": "Request error", "correlationId": "550e8400-e29b-41d4-a716-446655440000", "err": { "name": "Error", "message": "Something went wrong", "stack": "Error: Something went wrong\n at /app/routes.js:42:11" }, "context": { "statusCode": 500, "path": "/users", "method": "GET" } } ``` -------------------------------- ### Run NestJS Application Source: https://github.com/ayungavis/cenglu/blob/main/examples/nestjs/README.md Commands to start the NestJS application in different modes. 'start:dev' enables watch mode for automatic restarts during development. ```bash pnpm run start # watch mode pnpm run start:dev # production mode pnpm run start:prod ``` -------------------------------- ### License and Support Source: https://github.com/ayungavis/cenglu/blob/main/README.md Information regarding the project's license, and how to provide support. ```APIDOC ## License MIT ## Support If this saves you time, consider: - ⭐ Starring the repo - 🐛 Reporting bugs - 💡 Suggesting features - 🍺 Buying me a beer ``` -------------------------------- ### Create and Use Basic Logger Source: https://github.com/ayungavis/cenglu/blob/main/README.md Create a logger instance with service name and log level, then use it for basic logging. Ensure the service name is set for proper identification. ```typescript import { createLogger } from "cenglu"; const logger = createLogger({ service: "my-app", level: "info", }); logger.info("server started", { port: 3000 }); ``` -------------------------------- ### Example Custom Redaction Pattern Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx An example of a custom redaction pattern to mask API keys, using a regex to find 'api-key' or 'apikey' followed by a value, and replacing it with '[API_KEY_REDACTED]'. ```typescript { pattern: /api[_-]?key[:\s]+[\w-]+/gi, replacement: "[API_KEY_REDACTED]", name: "api-key", } ``` -------------------------------- ### Configure Initial Bindings Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/configuration.mdx Add context-specific data that will be included in every log message. This is useful for adding hostnames, PIDs, or region information. ```typescript const logger = createLogger({ bindings: { hostname: os.hostname(), pid: process.pid, region: process.env.AWS_REGION, }, }); logger.info("Server started"); // Output includes all bindings automatically ``` -------------------------------- ### LoggerContext API - get() Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/features/context-bindings.mdx Retrieve the current context object. ```APIDOC ## LoggerContext API - get() Get the current context: ```typescript const context = LoggerContext.get(); if (context) { console.log(context.correlationId); console.log(context.bindings); } ``` ``` -------------------------------- ### Development Environment Logging Setup with Cenglu Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Configure Cenglu for a development environment with pretty, colored console output. Disables sampling and uses a mock time function for testing. ```typescript const logger = createLogger({ service: "dev-app", level: "debug", // Pretty, colored output for terminals pretty: { enabled: true }, // Console only transports: [createConsoleTransport()], // No sampling in dev plugins: [], // Mock time for tests now: Date.now, }); ``` -------------------------------- ### Install Cenglu for Express Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/express.mdx Import necessary modules from cenglu and express for middleware integration. ```typescript import express from "express"; import { createLogger, expressMiddleware } from "cenglu"; ``` -------------------------------- ### Custom Type Guards Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx Examples of how to create custom type guards for Cenglu types. ```APIDOC ## Type Guards Cenglu doesn't export type guards, but you can create your own: ```typescript function isLogRecord(obj: unknown): obj is LogRecord { return ( typeof obj === "object" && obj !== null && "level" in obj && "msg" in obj && "time" in obj ); } function isErrorInfo(obj: unknown): obj is ErrorInfo { return ( typeof obj === "object" && obj !== null && ("message" in obj || "name" in obj || "stack" in obj) ); } ``` ``` -------------------------------- ### Implement a Monitoring Adapter for Log Records Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Example of a Cenglu adapter that sends log records to a monitoring service. This demonstrates integrating logging with external monitoring systems. ```typescript const monitoringAdapter: ProviderAdapter = { name: "monitoring", async handle(record) { await monitoring.track(record); }, }; ``` -------------------------------- ### Context Merging Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/data-flow.mdx Demonstrates the order of context merging in Cenglu, showing how global, child, async, bound, and call-site contexts are combined, with later sources overriding earlier ones. ```typescript // Example context merging const logger = createLogger({ bindings: { service: "api", env: "prod" } // 1. Global }); const childLogger = logger.child({ module: "users" // 2. Child bindings }); // In middleware (sets async context) LoggerContext.run({ requestId: "abc-123" }, () => { // 3. Async context childLogger .with({ operation: "create" }) // 4. Bound context .info("User created", { userId: 456 }); // 5. Call-site // Final context: { service, env, module, requestId, operation, userId } }); ``` -------------------------------- ### External Transport Setup with Pino Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-pino.mdx Integrate Pino with an external logging service like Datadog using a transport. Requires the 'pino-datadog' package and an API key. ```typescript import pino from "pino"; const logger = pino(pino.transport({ target: "pino-datadog", options: { apiKey: process.env.DD_API_KEY }, })); ``` -------------------------------- ### Winston Transport Array Configuration Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of configuring Winston with multiple transports (Console and File). ```typescript transports: [ new winston.transports.Console(), new winston.transports.File({ filename: "app.log" }), ] ``` -------------------------------- ### Basic Koa Middleware Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/middleware/koa.mdx Apply the cenglu koaMiddleware to a Koa application. The logger is automatically attached to the context for easy access within routes. ```typescript import Koa from "koa"; import { createLogger, koaMiddleware } from "cenglu"; const app = new Koa(); const logger = createLogger({ service: "api" }); // Apply middleware app.use(koaMiddleware(logger)); app.use(async (ctx) => { // Logger is automatically attached with request context ctx.logger.info("Processing request", { userId: ctx.query.userId }); ctx.body = { message: "Hello, World!" }; }); app.listen(3000); ``` -------------------------------- ### Cenglu Transport Array Configuration Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of configuring Cenglu with multiple transports using factory functions. ```typescript transports: [ createConsoleTransport(), createFileTransport({ dir: "./logs" }), ] ``` -------------------------------- ### Cenglu Console Transport Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of creating a console transport in Cenglu. It can be configured with options like stream. ```typescript import { createConsoleTransport } from "cenglu"; createConsoleTransport({ enabled: true, stream: process.stdout, }) ``` -------------------------------- ### Create and Manage Logger Resources Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Demonstrates the lifecycle of creating a logger, using it, and performing a graceful shutdown to flush buffers and close resources. Proper resource management prevents data loss and leaks. ```typescript // 1. Create const logger = createLogger({ transports: [fileTransport], // Allocates file handles plugins: [batchingPlugin()], // Allocates buffers }); // 2. Use logger.info("Application started"); // 3. Graceful shutdown process.on("SIGTERM", async () => { logger.info("Shutting down..."); // 4. Flush (ensure all logs are written) await logger.flush(); // 5. Close (cleanup resources) await logger.close(); process.exit(0); }); ``` -------------------------------- ### Winston Custom Format Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Example of creating a custom log format in Winston using timestamp and printf. ```typescript const logger = winston.createLogger({ format: winston.format.combine( winston.format.timestamp(), winston.format.printf(info => { return `${info.timestamp} [${info.level}]: ${info.message}`; }) ), }); ``` -------------------------------- ### Run Express Project with Bun Source: https://github.com/ayungavis/cenglu/blob/main/examples/express/README.md Execute your Express application using the Bun runtime. ```bash bun run index.ts ``` -------------------------------- ### Create a Basic Logger Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/index.mdx Initialize a logger instance with a service name and log level. Use this for general application logging. ```typescript import { createLogger } from "cenglu"; const logger = createLogger({ service: "my-app", level: "info", }); logger.info("Application started", { port: 3000 }); ``` -------------------------------- ### Configure Default and No-Color Themes Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/logger.mdx Create loggers with either the default colored theme or a theme that disables colors for plain text output. Ensure `createLogger` is imported. ```typescript 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 }, }); ``` -------------------------------- ### Configure Multiple Transports Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/system-design.mdx Example of configuring a logger with multiple transports. Logs will be written to all specified transports. ```typescript const logger = createLogger({ transports: [ consoleTransport, fileTransport, httpTransport, ], }); // Log is written to ALL transports logger.info("Application started"); ``` -------------------------------- ### Set up Winston Log Stream Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/guides/migration-from-winston.mdx Create a stream from Winston logger to listen for 'log' events. ```typescript const stream = logger.stream({ level: "info", }); stream.on("log", (info) => { console.log(info); }); ``` -------------------------------- ### Access Logger Config Properties Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx Example of accessing specific properties from the logger's configuration object. ```typescript const { structured, sampling } = logger.config; ``` -------------------------------- ### Access Logger State Properties Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/types.mdx Example of accessing specific properties from the logger's state object. ```typescript const { level, service, bindings } = logger.state; ``` -------------------------------- ### Basic Filter Plugin Setup Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/built-in-plugins.mdx Initialize the filter plugin to control log output based on minimum level and a custom filter function. The filter function should return `false` to drop a log record. ```typescript import { createLogger, filterPlugin } from "cenglu"; const logger = createLogger({ plugins: [ filterPlugin({ // Only log errors and above minLevel: "error", // Custom filter function filter: (record) => { // Drop health check logs if (record.msg.includes("health check")) { return false; } // Drop logs without userId if (!record.context?.userId) { return false; } return true; }, }), ], }); ``` -------------------------------- ### Get Current Log Level Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/api/logger.mdx Retrieve the current minimum log level that the logger is configured to use. ```typescript const currentLevel = logger.getLevel(); console.log(`Current level: ${currentLevel}`); // "info" ``` -------------------------------- ### Create a Basic Logger Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/getting-started/basic-usage.mdx Initialize a logger instance with default settings. Use this for simple logging needs. ```typescript import { createLogger } from "cenglu"; const logger = createLogger(); logger.info("Hello, world!"); ``` -------------------------------- ### Sampling Plugin Implementation Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/architecture/data-flow.mdx Provides an example implementation of a sampling plugin. This plugin demonstrates how to conditionally drop log records, in this case, dropping 90% of debug logs based on a random check. ```typescript // Sampling plugin { name: "sampling", order: 10, onRecord(record: LogRecord): LogRecord | null { if (record.level === "debug" && Math.random() > 0.1) { return null; // Drop 90% of debug logs } return record; // Keep the log } } ``` -------------------------------- ### Cenglu Plugin Package JSON Example Source: https://github.com/ayungavis/cenglu/blob/main/docs/content/docs/plugins/creating-plugins.mdx Configuration for a Cenglu plugin's `package.json` file. It specifies the main entry point, types, keywords, and peer dependencies, ensuring compatibility with the Cenglu logging library. ```json { "name": "cenglu-plugin-myplugin", "version": "1.0.0", "main": "./dist/index.js", "types": "./dist/index.d.ts", "keywords": ["cenglu", "logging", "plugin"], "peerDependencies": { "cenglu": "^2.0.0" } } ```