Getting Started

Introduction

A modern TypeScript logger built for everything you ship. Simple structured logs, wide events, and structured errors in one API — drop-in for console.log, pino, or consola.

evlog is a modern TypeScript logger built for everything you ship. It gives you simple structured logs (a drop-in for console.log, pino, or consola), wide events that accumulate context across an operation, and structured errors that explain why they happened — all in one API, all behind the same drain pipeline. Use it in CLIs, libraries, background jobs, edge workers, and HTTP handlers without switching loggers.

Inspired by Logging Sucks by Boris Tane.

Philosophy

Traditional logging is broken. Your logs are scattered across dozens of files. Each request generates 10+ log lines. When something goes wrong, you're left grep-ing through noise hoping to find signal.

evlog takes a different approach:

Structured Logging

Replace console.log with typed, structured events that flow through a drain pipeline. Same level filtering, redaction, and pretty/JSON output as pino or consola.

Wide Events

Accumulate context over any unit of work (a request, script, or job) and emit once. The two modes coexist — neither is an upgrade of the other.

Structured Errors

Errors that explain why they occurred and how to fix them.

Pretty for Dev

Human-readable in development, machine-parseable JSON in production.
Not running an HTTP framework? See Standalone TypeScript for scripts, workers, and CLIs, and Cloudflare Workers for the edge runtime.

Why evlog over pino, winston, or consola

evlog is a fully-featured general-purpose logger that happens to also do wide events. Concretely:

  • Zero transitive dependencies and ~5 kB gzip — nothing to audit, nothing that breaks on the next Node LTS. Benchmarked at ~3 µs/request, faster than pino in the wide event lifecycle and competitive on every other path.
  • Same API in every context — scripts, frameworks, edge runtimes, browser, library code. No pino-http vs pino split, no separate consola reporters per environment.
  • Structured errors with why / fix / link built in — your error toast finally tells users what went wrong and what to do, your on-call stops reverse-engineering stack traces.
  • Wide events as a free upgrade path — when you need to correlate context across an operation, the same logger gives you log.set + log.emit instead of stitching log lines together later.

See the full feature comparison (parity matrix, honest gaps, and migration snippets) for a side-by-side with pino, winston, and consola.

Three Ways to Log

evlog provides three APIs for different contexts. You can use all three in the same project.

Simple Logging

Fire-and-forget structured logs. Replace console.log, consola, or pino:

src/index.ts
import { log } from 'evlog'

log.info('auth', 'User logged in')
log.error({ action: 'payment', error: 'card_declined', userId: 42 })

Wide Events

Accumulate context progressively over any operation, then emit a single comprehensive event:

import { createLogger } from 'evlog'

const log = createLogger({ jobId: 'sync-001', queue: 'emails' })
log.set({ batch: { size: 50, processed: 50 } })
log.emit()

One log, all context. Everything you need to understand what happened.

Structured Errors

Errors with actionable context: why it happened, how to fix it, and a link to docs:

import { createError } from 'evlog'

throw createError({
  message: 'Payment failed',
  status: 402,
  why: 'Card declined by issuer (insufficient funds)',
  fix: 'Try a different payment method or contact your bank',
  link: 'https://docs.example.com/payments/declined',
})

Why Context Matters

We're entering an era where AI agents build, debug, and maintain applications. These agents need structured context to work effectively:

  • why: The root cause, so the agent understands what went wrong
  • fix: An actionable solution the agent can suggest or apply
  • link: Documentation for complex issues

Traditional console.log and generic throw new Error() provide no actionable context. evlog's structured output is designed for both humans and AI to parse and act on.

Next Steps