Wide events and structured errors for TypeScript. One log per request, full context, errors that explain why and how to fix.
Simple API
export default defineEventHandler(async (event) => {
const log = useLogger(event)
log.set({ user: { id: user.id, plan: user.plan } })
log.set({ cart: { items: 3, total: 9999 } })
return { success: true }
})✓ One log with full context
Structured Errors
throw createError({
message: 'Payment failed',
status: 402,
why: 'Card declined by issuer',
fix: 'Try a different card',
})✓ Actionable error messages
Agent Ready
Structured fields, machine-readable context, and actionable metadata — everything an AI agent needs to diagnose and resolve issues on its own.
Card declined by issuer — insufficient funds
Pro plan user (#1842) blocked on payment
Prompt for alternate payment method
stripe.com/docs/declines/codes
✓ Auto-created issue PAY-4521
Drain Pipeline
Batched writes, automatic retries with backoff, and fan-out to multiple destinations. Your logs flow through a pipeline that never blocks your response.
Non-blocking
Pipeline runs in the background. Your response ships immediately.
Guaranteed delivery
Exponential backoff with jitter ensures logs reach every destination.
Bring your own drain
Write a simple function to send logs anywhere.
import { createDrainPipeline } from 'evlog/pipeline'
import { createAxiomDrain } from 'evlog/axiom'
import { createSentryDrain } from 'evlog/sentry'
const pipeline = createDrainPipeline({
drains: [
createAxiomDrain(),
createSentryDrain(),
],
batchSize: 50,
flushInterval: 5000,
})Frameworks
One module for Nuxt. First-class Next.js support. Standalone API for everything else.
export default defineEventHandler(async (event) => {
const log = useLogger(event)
const { cartId } = await readBody(event)
const cart = await db.findCart(cartId)
log.set({ cart: { items: cart.items.length, total: cart.total } })
const charge = await stripe.charge(cart.total)
log.set({ stripe: { chargeId: charge.id } })
if (!charge.success) {
throw createError({
status: 402,
message: 'Payment failed',
why: charge.decline_reason,
fix: 'Try a different payment method',
})
}
return { orderId: charge.id }
})
Wide events, structured errors, dead simple setup.
Set up evlog in 10 minutes. Your future self will thank you.