适配器
适配器允许您将日志发送到外部可观测性平台。evlog 提供内置适配器以支持流行的服务,并且您可以为任何目标创建自定义适配器。
适配器如何工作
适配器在每次请求完成后接收一个 DrainContext,并将数据发送到外部服务。排水过程在 fire-and-forget 模式下运行,这意味着它永远不会阻塞 HTTP 响应。
如何连接适配器取决于您使用的框架:
// server/plugins/evlog-drain.ts
import { createAxiomDrain } from 'evlog/axiom'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
})
import { createAxiomDrain } from 'evlog/axiom'
app.use(evlog({ drain: createAxiomDrain() }))
import { createAxiomDrain } from 'evlog/axiom'
app.use(evlog({ drain: createAxiomDrain() }))
import { createAxiomDrain } from 'evlog/axiom'
await app.register(evlog, { drain: createAxiomDrain() })
import { createAxiomDrain } from 'evlog/axiom'
app.use(evlog({ drain: createAxiomDrain() }))
import { createAxiomDrain } from 'evlog/axiom'
EvlogModule.forRoot({ drain: createAxiomDrain() })
import { createAxiomDrain } from 'evlog/axiom'
initLogger({ drain: createAxiomDrain() })
Serverless 支持: 在 Cloudflare Workers 和 Vercel Edge 上,evlog 会自动使用
waitUntil() 来确保在运行时终止前排水完成。无需额外配置。可用适配器
独立使用
在纯 TypeScript 或 Bun 脚本(无 HTTP 框架)中使用 initLogger 中的 drain 选项。每个发出的事件都会自动被排出。
index.ts
import type { DrainContext } from 'evlog'
import { initLogger, log, createRequestLogger } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'
const pipeline = createDrainPipeline<DrainContext>()
const drain = pipeline(createAxiomDrain())
initLogger({
env: { service: 'my-script' },
drain,
})
log.info({ action: 'job_started' }) // 自动排出
const reqLog = createRequestLogger({ method: 'POST', path: '/process' })
reqLog.set({ processed: 42 })
reqLog.emit() // 自动排出
await drain.flush()
请参阅完整的 bun-script 示例,了解一个实际的批处理脚本。
多目标发送
通过组合排水器同时将日志发送到多个服务:
src/index.ts
import { createAxiomDrain } from 'evlog/axiom'
import { createOTLPDrain } from 'evlog/otlp'
const axiom = createAxiomDrain()
const otlp = createOTLPDrain()
const drain = async (ctx) => {
await Promise.allSettled([axiom(ctx), otlp(ctx)])
}
然后将 drain 传递给您的框架:
// server/plugins/evlog-drain.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', drain)
})
app.use(evlog({ drain }))
app.use(evlog({ drain }))
await app.register(evlog, { drain })
app.use(evlog({ drain }))
EvlogModule.forRoot({ drain })
initLogger({ drain })
排出上下文
每个适配器都会接收一个带有以下内容的 DrainContext:
| 字段 | 类型 | 描述 |
|---|---|---|
event | WideEvent | 包含所有累积上下文的完整日志事件 |
request | object | 请求元数据(method、path、requestId) |
headers | object | 安全的 HTTP 头(敏感头会被过滤) |
安全性: 敏感头信息(如
authorization、cookie、x-api-key 等)会自动被过滤,不会传递给适配器。零配置设置
所有适配器都支持通过环境变量自动配置,无需更改代码即可在不同环境中部署。
每个适配器读取以 NUXT_* 为前缀的变量(适用于 Nuxt/Nitro 的 runtimeConfig)和无前缀的备用变量(适用于任何框架):
.env
# Axiom (NUXT_AXIOM_* 或 AXIOM_*)
AXIOM_TOKEN=xaat-xxx
AXIOM_DATASET=my-logs
# OTLP (NUXT_OTLP_* 或 OTEL_*)
OTLP_ENDPOINT=https://otlp.example.com
# HyperDX (NUXT_HYPERDX_* 或 HYPERDX_*)
HYPERDX_API_KEY=<YOUR_HYPERDX_API_KEY_HERE>
# PostHog (NUXT_POSTHOG_* 或 POSTHOG_*)
POSTHOG_API_KEY=phc_xxx
# Sentry (NUXT_SENTRY_* 或 SENTRY_*)
SENTRY_DSN=https://key@o0.ingest.sentry.io/123
# Better Stack (NUXT_BETTER_STACK_* 或 BETTER_STACK_*)
BETTER_STACK_SOURCE_TOKEN=your-source-token
# Datadog (NUXT_DATADOG_* 或 DATADOG_* 或 DD_*)
DD_API_KEY=your-api-key
DD_SITE=datadoghq.eu
适配器会自动读取这些变量,因此只需调用 createXDrain() 而无需传入参数。