Logging Overview
evlog provides three logging APIs, each designed for a different context. You can use all three in the same project.
The Three Modes
Simple Logging
console.log, consola, or pino with log.info, log.error, log.warn, log.debug.Quick Comparison
Simple Logging (log)
One event per call. No accumulation, no lifecycle management.
import { log } from 'evlog'
log.info('auth', 'User logged in')
log.error({ action: 'payment', error: 'card_declined', userId: 42 })
Wide Events (createLogger / createRequestLogger)
One event per unit of work. Accumulate context progressively, emit when done.
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()
createRequestLogger is a thin wrapper around createLogger that pre-populates method, path, and requestId.
Request Logging (framework middleware)
Framework integrations create a wide event logger automatically on each request. useLogger(event) retrieves the logger that's already attached to the request context:
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
})
useLogger(event) doesn't create a logger, it retrieves the one the framework middleware already attached to the event. Each framework has its own way to access it (useLogger, req.log, c.get('log'), etc.). In Nuxt, useLogger is auto-imported.When to Use What
log | createLogger / createRequestLogger | Framework middleware | |
|---|---|---|---|
| Use case | Quick one-off events | Scripts, jobs, workers, queues, HTTP without a framework | API routes with a framework integration |
| Context | Single call | Accumulate with set() | Accumulate with set() |
| Emit | Immediate | Manual emit() | Automatic on response end |
| Lifecycle | None | You manage it | Framework manages it |
| Output | Console + drain | Console + drain | Console + drain + enrich |
log for quick structured logging. When you need to accumulate context across an operation, switch to createLogger (or createRequestLogger for HTTP contexts). When using a framework integration, the middleware handles everything, just call useLogger(event) to retrieve the logger.Shared Features
All three modes share the same foundation:
- Pretty output in development, JSON in production (default, no configuration needed)
- Drain pipeline to send events to Axiom, Sentry, PostHog, and more
- Structured errors with
why,fix, andlinkfields - Sampling to control log volume in production
- Zero dependencies, ~5 kB gzip
Next Steps
- Simple Logging: The
logAPI in detail - Wide Events: Accumulating context and emitting events
- Structured Errors: Errors with actionable context
- Frameworks: Auto-managed request logging per framework
Agent Skills
AI-assisted code review and evlog adoption using Agent Skills. Let AI review your logging patterns and guide migration to wide events.
Simple Logging
Structured logging for everyday use. Replace console.log with log.info, log.error, log.warn, and log.debug. Fire-and-forget events with pretty output in dev and JSON in production.