Nitro
evlog 提供了适用于 Nitro v3 和 Nitro v2(nitropack)的模块。该模块会钩入请求生命周期,创建一个请求范围内的日志记录器,可通过 useLogger(event) 访问,并在响应完成时发出一个广泛事件。
在我的 Nitro 应用中设置 evlog
快速开始
1. 安装
pnpm add evlog
bun add evlog
yarn add evlog
npm install evlog
2. 添加模块
import { defineConfig } from 'nitro'
import evlog from 'evlog/nitro/v3'
export default defineConfig({
modules: [
evlog({
env: { service: 'my-app' },
}),
],
})
import { defineNitroConfig } from 'nitropack/config'
import evlog from 'evlog/nitro'
export default defineNitroConfig({
modules: [
evlog({
env: { service: 'my-app' },
}),
],
})
广泛事件
在请求过程中,使用 useLogger(event) 逐步构建上下文。evlog 会在请求完成时发出一个单一的广泛事件。
import { defineHandler } from 'nitro/h3'
import { useLogger } from 'evlog/nitro/v3'
export default defineHandler(async (event) => {
const log = useLogger(event)
const body = await readBody(event)
log.set({ user: { id: body.userId } })
log.set({ cart: { items: body.items.length, total: body.total } })
return { success: true }
})
import { defineEventHandler, readBody } from 'h3'
import { useLogger } from 'evlog/nitro'
export default defineEventHandler(async (event) => {
const log = useLogger(event)
const body = await readBody(event)
log.set({ user: { id: body.userId } })
log.set({ cart: { items: body.items.length, total: body.total } })
return { success: true }
})
一个请求,一条日志行,包含所有上下文信息:
10:23:45 INFO [my-app] POST /api/checkout 200 in 145ms
├─ user: id=usr_123
├─ cart: items=3 total=14999
└─ requestId: a1b2c3d4-...
Nitro 使用 useLogger(event)(事件绑定作用域),而不是 AsyncLocalStorage,所以 log.fork() 目前还不可用。对于 AI SDK 流式响应,evlog 会延迟宽事件的发出,直到响应体结束,因此 createAILogger(log) 元数据会保留在同一个请求事件上。仅当代码在宽事件实际发出后调用 set() 时,才会应用发出后的警告——例如在非流式处理器或后台工作中。请参阅 宽事件 — 发出后。
错误处理
createError 会生成包含 why、fix 和 link 字段的结构化错误,帮助人类和 AI 代理理解问题所在。
import { defineHandler } from 'nitro/h3'
import { useLogger, createError } from 'evlog/nitro/v3'
export default defineHandler(async (event) => {
const log = useLogger(event)
throw createError({
status: 402,
message: 'Payment failed',
why: 'Card declined by issuer',
fix: 'Try a different payment method',
})
})
import { defineEventHandler } from 'h3'
import { useLogger } from 'evlog/nitro'
import { createError } from 'evlog'
export default defineEventHandler(async (event) => {
const log = useLogger(event)
throw createError({
status: 402,
message: 'Payment failed',
why: 'Card declined by issuer',
fix: 'Try a different payment method',
})
})
evlog/nitro/v3 导入 createError —— 它封装了 Nitro 的错误处理机制。在 Nitro v2 中,请直接从 evlog 导入 createError。配置
请参阅 配置参考,了解所有可用选项(enabled、pretty、silent、sampling 等)。
路由过滤
使用 include 和 exclude 控制哪些路由被记录,以及使用 routes 为不同的路由组分配不同的服务名称:
import { defineConfig } from 'nitro'
import evlog from 'evlog/nitro/v3'
export default defineConfig({
modules: [
evlog({
include: ['/api/**'],
exclude: ['/api/health'],
routes: {
'/api/auth/**': { service: 'auth-service' },
'/api/payment/**': { service: 'payment-service' },
},
})
],
})
import { defineNitroConfig } from 'nitropack/config'
import evlog from 'evlog/nitro'
export default defineNitroConfig({
modules: [
evlog({
include: ['/api/**'],
exclude: ['/api/health'],
routes: {
'/api/auth/**': { service: 'auth-service' },
'/api/payment/**': { service: 'payment-service' },
},
})
],
})
include 和 exclude,则会被排除。排水(Drain)与增强器(Enrichers)
使用 Nitro 插件钩子将日志发送到外部服务并增强上下文信息。
排水插件
import type { DrainContext } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'
const pipeline = createDrainPipeline<DrainContext>({
batch: { size: 50, intervalMs: 5000 },
retry: { maxAttempts: 3 },
})
const drain = pipeline(createAxiomDrain())
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', drain)
})
definePlugin 替代 defineNitroPlugin。增强器插件
import { createUserAgentEnricher, createGeoEnricher } from 'evlog/enrichers'
const enrichers = [createUserAgentEnricher(), createGeoEnricher()]
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:enrich', (ctx) => {
for (const enricher of enrichers) enricher(ctx)
})
})
采样
头部采样
按百分比随机保留各层级的日志。在请求完成前执行。
import { defineConfig } from 'nitro'
import evlog from 'evlog/nitro/v3'
export default defineConfig({
modules: [
evlog({
sampling: {
rates: { info: 10, warn: 50, debug: 5 },
keep: [
{ duration: 1000 },
{ status: 400 },
],
},
})
],
})
import { defineNitroConfig } from 'nitropack/config'
import evlog from 'evlog/nitro'
export default defineNitroConfig({
modules: [
evlog({
sampling: {
rates: { info: 10, warn: 50, debug: 5 },
keep: [
{ duration: 1000 },
{ status: 400 },
],
},
})
],
})
每个层级都是 0 到 100 的百分比。未配置的层级默认保留 100%(保留全部)。
自定义尾部采样
对于超出状态、时长和路径的条件,使用 evlog:emit:keep 钩子:
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:emit:keep', (ctx) => {
const user = ctx.context.user as { premium?: boolean } | undefined
if (user?.premium) ctx.shouldKeep = true
})
})
error: 0 才能丢弃它们。下一步
深入了解 Nitro 集成: