Skip to content
Back to projects

OpenLog — Structured Logging Library

A lightweight TypeScript library for structured, context-aware logging in Node.js applications, with built-in OpenTelemetry trace correlation.

TypeScript Node.js OpenTelemetry Jest npm
Screenshot of OpenLog — Structured Logging Library

The Problem

Every Node.js project I worked on had a different logging setup — some using raw console.log, some using Winston, some using Pino. None of them correlated logs to distributed traces out of the box, which made debugging production incidents painful: you’d have a trace ID in Datadog but couldn’t find the matching logs without manual grep work.

My Approach

I wanted a library that was: (1) zero-config for the happy path, (2) automatically injected OpenTelemetry trace/span IDs into every log line, (3) structured (JSON output for production, pretty-printed for development), and (4) tiny — no bloated dependency tree.

I studied the internals of Pino and Winston, then designed the API contract first (what would the ideal call site look like?) before writing a single line of implementation.

What I Built

The library exposes a simple factory function that creates a logger pre-configured for the environment:

const log = createLogger({ service: 'payment-service' });
log.info('Payment processed', { orderId, amount, currency });
// → {"level":"info","service":"payment-service","msg":"Payment processed",
//    "orderId":"ord_123","traceId":"abc123","spanId":"def456","timestamp":"..."}

Key features:

  • Automatic trace correlation — reads active OpenTelemetry span from context, adds traceId and spanId to every log
  • Child loggerslog.child({ requestId }) propagates context through request lifecycle
  • Log level filtering — env-controlled, zero-overhead when below threshold
  • Transport abstraction — ships stdout by default, extensible for Datadog/Logtail/etc.

Results

  • 1,200+ weekly npm downloads after 3 months
  • Adopted as standard logging library across all new Node.js services at my employer
  • Full test coverage (98%) — extensive edge case testing for async context propagation
  • Listed in the OpenTelemetry JS contrib ecosystem docs as a community library

Key Learnings

AsyncLocalStorage for context propagation is powerful but has surprising gotchas with unhandled promise rejections — they can “escape” the storage context. The solution was wrapping the request handler at the framework level, not just at the logger level.