Introduction
evlog is a TypeScript logging library that helps you understand what happened in your app. Start with structured logs, bring a request’s context together in one wide event, and turn failures into errors that explain what went wrong and how to fix it.
Use it in your next project or introduce it alongside your existing logger. The Quick Start gets you going; the migration examples show how to bring familiar logging patterns to evlog.
Inspired by Logging Sucks by Boris Tane. The separate evlog CLI helps you explore your logs and spot missing logging patterns with static checks.
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
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
Structured Errors
Pretty for Dev
Why evlog over pino, winston, or consola
evlog is a fully-featured general-purpose logger that happens to also do wide events. Concretely:
- Zero runtime dependencies in the core package. Start with the logger and add integrations as you need them. See Performance for bundle sizes and benchmarks.
- Same API in every context: scripts, frameworks, edge runtimes, browser, library code. No
pino-httpvspinosplit, no separateconsolareporters per environment. - Structured errors with
why/fix/linkbuilt 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.emitinstead 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.
Pick one of 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:
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()
import { createRequestLogger } from 'evlog'
const log = createRequestLogger({ method: 'POST', path: '/api/checkout' })
log.set({ user: { id: 1, plan: 'pro' } })
log.emit()
import { useLogger } from 'evlog'
export default defineEventHandler(async (event) => {
const log = useLogger(event)
log.set({ user: { id: 1, plan: 'pro' } })
return { success: true }
// auto-emitted on response end
})
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',
})
{
"statusCode": 402,
"message": "Payment failed",
"data": {
"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 one event beats ten lines
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 wrongfix: An actionable solution the agent can suggest or applylink: 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
- Try evlog: follow Installation and the Quick Start.
- Decide whether it fits your project: read Choosing a TypeScript Logger, or Why start with evlog for a new application.
- Explore the concepts: the Logging Overview connects simple logs, wide events, and structured errors.