.agents/skills/review-logging-patterns/references/code-review.md
Use this checklist when reviewing code for logging best practices and evlog adoption.
Run through these checks first to identify improvement opportunities:
Search for these patterns:
// ❌ Patterns to find and transform
console.log(...)
console.error(...)
console.warn(...)
console.info(...)
console.debug(...)
Questions to ask:
Search for these patterns:
// ❌ Generic errors
throw new Error('...')
throw Error('...')
// ❌ Re-throwing without context
catch (error) {
throw error
}
// ❌ Logging and throwing
catch (error) {
console.error(error)
throw error
}
Questions to ask:
why explaining the root cause?fix suggesting a solution?cause?For each API route/handler, check:
// ❌ Missing request context
export default defineEventHandler(async (event) => {
// No logging at all, or scattered console.logs
})
Questions to ask:
// ❌ Before
console.log('Processing user:', userId)
// ✅ After - if part of a larger operation
log.set({ user: { id: userId } })
// ✅ After - if standalone debug
log.debug('user', `Processing user ${userId}`)
// ❌ Before
console.log('Starting checkout')
console.log('User:', user.id)
console.log('Cart items:', cart.items.length)
console.log('Total:', cart.total)
// ✅ After
log.info({
action: 'checkout',
user: { id: user.id },
cart: { items: cart.items.length, total: cart.total },
})
// server/api/process.post.ts
// ❌ Before
export default defineEventHandler(async (event) => {
console.log('Request started')
const user = await getUser(event)
console.log('User loaded')
const result = await processData(user)
console.log('Processing complete')
return result
})
// ✅ After (Nuxt - auto-imported, no import needed)
// For Nitro v3: import { useLogger } from 'evlog/nitro/v3'
// For Nitro v2: import { useLogger } from 'evlog/nitro'
export default defineEventHandler(async (event) => {
const log = useLogger(event)
const user = await getUser(event)
log.set({ user: { id: user.id } })
const result = await processData(user)
log.set({ result: { id: result.id } })
return result
// emit() called automatically
})
// ❌ Before
throw new Error('Failed to create user')
// ✅ After
throw createError({
message: 'Failed to create user',
why: 'Email address already registered',
fix: 'Use a different email or log in to existing account',
link: 'https://your-app.com/docs/registration',
})
// ❌ Before
try {
await externalApi.call()
} catch (error) {
throw new Error('API call failed')
}
// ✅ After
try {
await externalApi.call()
} catch (error) {
throw createError({
message: 'External API call failed',
why: `API returned: ${error.message}`,
fix: 'Check API credentials and try again',
link: 'https://api-docs.example.com/errors',
cause: error,
})
}
// ❌ Before
try {
await riskyOperation()
} catch (error) {
console.error('Operation failed:', error)
throw error
}
// ✅ After
try {
await riskyOperation()
} catch (error) {
log.error(error, { step: 'riskyOperation' })
throw createError({
message: 'Operation failed',
why: error.message,
fix: 'Check input and retry',
cause: error,
})
}
// server/api/orders.post.ts
// ❌ Before
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const result = await processOrder(body)
return result
})
// ✅ After (Nuxt - auto-imported, no import needed)
// For Nitro v3: import { useLogger } from 'evlog/nitro/v3'
// For Nitro v2: import { useLogger } from 'evlog/nitro'
import { createError } from 'evlog'
export default defineEventHandler(async (event) => {
const log = useLogger(event)
const body = await readBody(event)
log.set({ order: { items: body.items?.length } })
try {
const result = await processOrder(body)
log.set({ result: { orderId: result.id, status: result.status } })
return result
} catch (error) {
log.error(error, { step: 'processOrder' })
throw createError({
message: 'Order processing failed',
why: error.message,
fix: 'Check the order data and try again',
})
}
// emit() called automatically
})
console.log statements in production codeuseLogger(event) (Nuxt/Nitro) or createRequestLogger() (standalone)log.set() throughout the requestemit() is automatic with useLogger(), manual with createRequestLogger()createError() instead of new Error() (import from evlog)message and appropriate status codewhy explaining root causefix with actionable stepslink to docscauseinternal, not message / why / fixerror.data.data| Anti-Pattern | Fix |
|---|---|
Multiple console.log in one function | Single wide event with useLogger(event).set() |
throw new Error('...') | throw createError({ message, status, why, fix }) |
console.error(e); throw e | log.error(e); throw createError(...) |
| No logging in request handlers | Add useLogger(event) (Nuxt/Nitro) or createRequestLogger() (standalone) |
| Flat log data | Grouped objects: { user: {...}, cart: {...} } |
| Abbreviated field names | Descriptive names: userId not uid |
Use these when leaving review feedback:
Consider using evlog's wide event pattern here. Instead of multiple console.log statements, use
useLogger(event)to accumulate context and emit a single comprehensive event.
This error would benefit from evlog's structured error pattern. Consider using
import { createError } from 'evlog'andcreateError({ message, status, why, fix })to provide more debugging context.
This handler would benefit from request-scoped logging. Add
useLogger(event)at the start to capture context throughout the request lifecycle.
Nice use of wide events here! The context is well-structured and will be very useful for debugging.