# LogLayer > A structured logging library with a fluent API for Typescript / Javascript. It separates log data into context (persistent), metadata (per-message), and errors with support for 25+ transports and plugins. ## Installation ``` npm install loglayer ``` ## Quick Start ```typescript import { LogLayer, ConsoleTransport } from 'loglayer' import type { ILogLayer } from 'loglayer' const log: ILogLayer = new LogLayer({ transport: new ConsoleTransport({ logger: console, }), }) log.info('Hello world!') ``` ## Log Levels ```typescript log.trace('Detailed debugging') log.debug('Debug information') log.info('Informational message') log.warn('Warning message') log.error('Error occurred') log.fatal('Critical failure') // Multiple parameters log.info('User', 123, 'logged in') ``` ## Metadata (per-message data) ```typescript // Attach structured data to a single log entry log.withMetadata({ userId: '123', action: 'login' }).info('User logged in') // Log metadata without a message log.metadataOnly({ status: 'healthy', cpu: '45%' }) ``` ## Context (persistent data across all log entries) ```typescript // Set context - persists across all subsequent logs log.withContext({ requestId: 'abc-123', service: 'auth' }) log.info('Processing') // includes requestId and service log.info('Done') // still includes requestId and service // Read, clear, mute log.getContext() log.clearContext() // clear all log.clearContext(['requestId']) // clear specific keys log.muteContext() // temporarily disable log.unMuteContext() ``` ## Error Handling ```typescript // Error with a message log.withError(new Error('Connection failed')).error('DB error') // Error only (no extra message) log.errorOnly(new Error('Connection failed')) // Combine error with metadata log.withError(new Error('Timeout')) .withMetadata({ query: 'SELECT *', duration: 1500 }) .error('Query failed') ``` ## Error Serialization (recommended) ```typescript import { serializeError } from 'serialize-error' // npm install serialize-error const log: ILogLayer = new LogLayer({ errorSerializer: serializeError, transport: new ConsoleTransport({ logger: console }), }) ``` ## Lazy Evaluation ```typescript import { LogLayer, lazy } from 'loglayer' // Context: re-evaluated on every log call log.withContext({ memoryUsage: lazy(() => process.memoryUsage().heapUsed), }) // Metadata: evaluated once for that log entry log.withMetadata({ data: lazy(() => JSON.stringify(largeObject)), }).debug('Processing result') // metadataOnly: same behavior log.metadataOnly({ status: lazy(() => getHealthStatus()), }) // Async lazy (metadata only) — must be awaited await log.withMetadata({ result: lazy(async () => await fetchResult()), }).info('Done') await log.metadataOnly({ result: lazy(async () => await fetchResult()), }) // Callbacks are NOT invoked when the log level is disabled ``` ## Configuration ```typescript const log: ILogLayer = new LogLayer({ // Required transport: new ConsoleTransport({ logger: console }), // Optional prefix: '[MyApp]', // prepended to all messages enabled: true, // enable/disable logging contextFieldName: 'context', // nest context under a field (default: flattened) metadataFieldName: 'metadata', // nest metadata under a field (default: flattened) errorFieldName: 'err', // field name for errors (default: 'err') errorSerializer: (err) => ({ message: err.message, stack: err.stack }), copyMsgOnOnlyError: false, // copy error.message as log message in errorOnly() errorFieldInMetadata: false, // nest error inside metadata field muteContext: false, muteMetadata: false, plugins: [], }) ``` ## Groups (route logs to specific transports) ```typescript const log: ILogLayer = new LogLayer({ transport: [ new ConsoleTransport({ id: 'console', logger: console }), new DatadogTransport({ id: 'datadog', logger: datadog }), ], groups: { database: { transports: ['datadog'], level: 'error' }, auth: { transports: ['datadog', 'console'], level: 'warn' }, }, ungroupedBehavior: 'all', // 'all' (default) | 'none' | string[] }) // Per-log tagging log.withGroup('database').error('Connection lost') log.withGroup(['database', 'auth']).error('Auth DB failure') // Persistent tagging (child logger) const dbLogger = log.withGroup('database') dbLogger.error('Pool exhausted') // Runtime management log.disableGroup('database') log.setGroupLevel('database', 'debug') log.setActiveGroups(['database']) // only this group active log.setActiveGroups(null) // all groups active // Env variable: LOGLAYER_GROUPS=database:debug,auth:warn ``` ## Child Loggers ```typescript const parentLog: ILogLayer = new LogLayer({ transport: new ConsoleTransport({ logger: console }), }) parentLog.withContext({ service: 'api' }) // Child inherits config, context, plugins, and groups const childLog = parentLog.child() childLog.withContext({ handler: 'users' }) childLog.info('Request received') // has both service and handler context // Group config is shared by reference — runtime changes propagate both ways // Persistent group tags (via withGroup()) are copied independently ``` ## Message Prefixing ```typescript const log: ILogLayer = new LogLayer({ prefix: '[MyApp]', transport: new ConsoleTransport({ logger: console }), }) log.info('Started') // "[MyApp] Started" // Or dynamically const prefixed = log.withPrefix('[Auth]') prefixed.info('Login') // "[Auth] Login" ``` ## Log Level Control Log levels are checked at three independent tiers. A log must pass all applicable tiers: 1. **LogLayer (global)** — `setLevel()`, `enableLogging()` — checked first, before any processing 2. **Group** — `groups: { database: { level: 'error' } }` — only applies to grouped logs 3. **Transport** — `new ConsoleTransport({ level: 'warn' })` — checked at dispatch time Log level managers control tier 1 only. ```typescript import { LogLevel } from 'loglayer' log.setLevel(LogLevel.warn) // only warn+ will log log.enableLogging() // turn on log.disableLogging() // turn off log.isLevelEnabled(LogLevel.debug) // check if level is active ``` ## Multiple Transports ```typescript const log: ILogLayer = new LogLayer({ transport: [ new ConsoleTransport({ logger: console }), new PinoTransport({ logger: pino() }), ], }) ``` ## Testing / Mocking ```typescript import { MockLogLayer } from 'loglayer' // No-op logger for unit tests - same API, does nothing const log = new MockLogLayer() ``` ## Available Transports Built-in: ConsoleTransport, StructuredTransport, BlankTransport Logging libraries: Pino, Winston, Bunyan, Consola, Log4js, Roarr, Signale, loglevel, LogTape, tslog, Tracer, Electron Log Cloud providers: DataDog, AWS CloudWatch, AWS Lambda Powertools, Google Cloud Logging, Azure Monitor, New Relic, Dynatrace, Sentry, Axiom, Better Stack, Logflare, Sumo Logic, VictoriaLogs Pretty Printers: Pretty Terminal, Simple Pretty Terminal Other: HTTP, Log File Rotation, OpenTelemetry ## Available Plugins - Filter: conditionally drop logs - Redaction: redact sensitive fields - Sprintf: printf-style string formatting - OpenTelemetry: add trace/span context - DataDog APM Trace Injector: inject DD trace IDs ## Documentation - [Getting Started](https://loglayer.dev/getting-started): Installation and basic usage - [Configuration](https://loglayer.dev/configuration): All configuration options - [Basic Logging](https://loglayer.dev/logging-api/basic-logging): Log level methods and message formatting - [Context](https://loglayer.dev/logging-api/context): Persistent context data - [Metadata](https://loglayer.dev/logging-api/metadata): Per-message structured data - [Error Handling](https://loglayer.dev/logging-api/error-handling): Error logging and serialization - [Lazy Evaluation](https://loglayer.dev/logging-api/lazy-evaluation): Deferred computation for context and metadata - [Child Loggers](https://loglayer.dev/logging-api/child-loggers): Creating inherited logger instances - [Log Level Control](https://loglayer.dev/logging-api/adjusting-log-levels): Managing log levels - [Transport Overview](https://loglayer.dev/transports/): All supported transports - [Transport Configuration](https://loglayer.dev/transports/configuration): Transport setup options - [Plugins Overview](https://loglayer.dev/plugins): Plugin system and available plugins - [Testing / Mocking](https://loglayer.dev/logging-api/unit-testing): MockLogLayer for tests - [TypeScript Tips](https://loglayer.dev/logging-api/typescript): TypeScript-specific guidance ## Optional - [Creating Transports](https://loglayer.dev/transports/creating-transports): Build custom transports - [Creating Plugins](https://loglayer.dev/plugins/creating-plugins): Build custom plugins - [Context Managers](https://loglayer.dev/context-managers/): Customize context inheritance behavior - [Log Level Managers](https://loglayer.dev/log-level-managers/): Customize log level behavior - [Mixins](https://loglayer.dev/mixins/): Extend LogLayer with custom methods - [ElysiaJS Integration](https://loglayer.dev/integrations/elysia): ElysiaJS plugin with request-scoped logging, optional `group` config to tag auto-logged messages with groups for routing/filtering - [Express Integration](https://loglayer.dev/integrations/express): Express middleware with request-scoped logging, optional `group` config to tag auto-logged messages with groups for routing/filtering - [Fastify Integration](https://loglayer.dev/integrations/fastify): Fastify integration with request-scoped logging, optional `group` config to tag auto-logged messages with groups for routing/filtering - [Hono Integration](https://loglayer.dev/integrations/hono): Hono integration with request-scoped logging, optional `group` config to tag auto-logged messages with groups for routing/filtering - [Koa Integration](https://loglayer.dev/integrations/koa): Koa middleware with request-scoped logging, optional `group` config to tag auto-logged messages with groups for routing/filtering - [Next.js Integration](https://loglayer.dev/example-integrations/nextjs): Next.js example - [Async Context Tracking](https://loglayer.dev/example-integrations/async-context): AsyncLocalStorage example