Quick Start
This guide covers the core APIs you'll use most often with evlog.
useLogger, log, createError, parseError). No import statements needed.useLogger (Server-Side)
Use useLogger(event) in any Nuxt/Nitro API route to get a request-scoped logger:
export default defineEventHandler(async (event) => {
// Get the request-scoped logger (auto-imported in Nuxt)
const log = useLogger(event)
// Accumulate context throughout the request
log.set({ user: { id: 1, plan: 'pro' } })
log.set({ cart: { items: 3, total: 9999 } })
// Process checkout...
const order = await processCheckout()
log.set({ orderId: order.id })
// Logger auto-emits when request ends - nothing else to do!
return { success: true, orderId: order.id }
})
10:23:45.612 INFO [my-app] POST /api/checkout 200 in 234ms
├─ user: id=1 plan=pro
├─ cart: items=3 total=9999
└─ orderId: ord_abc123
emit() call needed.When to use useLogger vs log
Use useLogger(event) | Use log |
|---|---|
| API routes, middleware, server plugins | One-off events outside request context |
| When you need to accumulate context | Quick debugging messages |
| For wide events (one log per request) | Client-side logging |
Service Identification
In multi-service architectures, differentiate which service a log belongs to using either route-based configuration or explicit service names.
Route-Based Configuration
Configure service names per route pattern in your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
env: {
service: 'default-service', // Fallback service name
},
routes: {
'/api/auth/**': { service: 'auth-service' },
'/api/payment/**': { service: 'payment-service' },
'/api/booking/**': { service: 'booking-service' },
},
},
})
Logs from routes matching these patterns will automatically include the configured service name:
21:57:10.442 INFO [auth-service] POST /api/auth/login 200 in 1ms
├─ requestId: 88ced16a-bef2-4483-86cb-2b4fb677ea52
├─ user: id=user_123 email=demo@example.com
└─ action: login
Explicit Service Parameter
Override the service name for specific routes using the second parameter of useLogger:
export default defineEventHandler((event) => {
// Explicitly set service name for this handler
const log = useLogger(event, 'legacy-service')
log.set({ action: 'process_legacy_request' })
return { success: true }
})
useLogger parameter > Route configuration > env.service > Auto-detected from environmentcreateError (Structured Errors)
Use createError() to throw errors with actionable context:
// server/api/checkout.post.ts
import { createError } from 'evlog'
throw createError({
message: 'Payment failed',
status: 402,
why: 'Card declined by issuer',
fix: 'Try a different payment method',
link: 'https://docs.example.com/payments/declined',
})
{
"statusCode": 402,
"message": "Payment failed",
"data": {
"why": "Card declined by issuer",
"fix": "Try a different payment method",
"link": "https://docs.example.com/payments/declined"
}
}
Error Fields
| Field | Required | Description |
|---|---|---|
message | Yes | What happened (user-facing) |
status | No | HTTP status code (default: 500) |
why | No | Technical reason (for debugging) |
fix | No | Actionable solution |
link | No | Documentation URL for more info |
cause | No | Original error (if wrapping) |
Frontend Integration
Use parseError() to extract all error fields on the client:
import { parseError } from 'evlog'
export async function checkout(cart: Cart) {
try {
await $fetch('/api/checkout', { method: 'POST', body: cart })
} catch (err) {
const error = parseError(err)
// Direct access to all fields
toast.add({
title: error.message,
description: error.why,
color: 'error',
actions: error.link
? [{ label: 'Learn more', onClick: () => window.open(error.link) }]
: undefined,
})
if (error.fix) {
console.info(`Fix: ${error.fix}`)
}
}
}
log (Simple Logging)
For quick one-off logs anywhere in your code:
// server/utils/auth.ts
log.info('auth', 'User logged in')
log.error({ action: 'payment', error: 'card_declined' })
log.warn('cache', 'Cache miss')
10:23:45.612 [auth] User logged in
10:23:45.613 ERROR [my-app] action=payment error=card_declined
10:23:45.614 [cache] Cache miss
useLogger) over simple logs when possible. Use log for truly one-off events that don't belong to a request.log (Client-Side)
The same log API works on the client side, outputting to the browser console:
<script setup lang="ts">
async function handleCheckout() {
log.info('checkout', 'User initiated checkout')
try {
await $fetch('/api/checkout', { method: 'POST' })
log.info({ action: 'checkout', status: 'success' })
} catch (err) {
log.error({ action: 'checkout', error: 'failed' })
}
}
</script>
export function useAnalytics() {
function trackEvent(event: string, data?: Record<string, unknown>) {
log.info('analytics', `Event: ${event}`)
if (data) {
log.debug({ event, ...data })
}
}
return { trackEvent }
}
In pretty mode (development), client logs appear with colored tags in the browser console:
[my-app] info { action: 'checkout', status: 'success' }
log is designed for debugging and development. For production analytics, use dedicated services like Plausible, PostHog, or Mixpanel.Wide Event Fields
Every wide event should include context from different layers:
// server/api/checkout.post.ts
const log = useLogger(event)
// Request context (often auto-populated)
log.set({ method: 'POST', path: '/api/checkout' })
// User context
log.set({ userId: 1, subscription: 'pro' })
// Business context
log.set({ cart: { items: 3, total: 9999 }, coupon: 'SAVE10' })
// Outcome
log.set({ status: 200, duration: 234 })
{
"level": "info",
"method": "POST",
"path": "/api/checkout",
"userId": 1,
"subscription": "pro",
"cart": { "items": 3, "total": 9999 },
"coupon": "SAVE10",
"status": 200,
"duration": 234
}
Next Steps
- Wide Events - Learn how to design effective wide events
- Structured Errors - Master error handling with evlog
- Best Practices - Security guidelines and production tips
Installation
Install evlog in your Nuxt, Nitro, Cloudflare Workers, or standalone TypeScript project. Configure sampling, log draining, and client transport.
Agent Skills
AI-assisted code review and evlog adoption using Agent Skills. Let AI review your logging patterns and guide migration to wide events.