框架
自定义集成
使用工具包 API 构建自定义的 evlog 框架集成,包含 createMiddlewareLogger、头部提取、AsyncLocalStorage 以及完整的 drain/enrich/keep 管道。
没有看到你使用的框架?evlog/toolkit 包暴露了与每个内置集成(Hono、Express、Fastify、Elysia、nestJS、SvelteKit)相同的构建模块。使用大约 50 行代码即可为任意 HTTP 框架构建功能完整的 evlog 中间件。
工具包 API 标记为 beta。其接口是稳定的(所有内置集成都在使用),但可能会根据社区反馈进行演进。
安装
pnpm add evlog
npm install evlog
bun add evlog
工具包包含什么
| 导出 | 用途 |
|---|---|
createMiddlewareLogger(opts) | 完整管道:创建日志器、路由过滤、尾部采样、发送、增强、排水 |
BaseEvlogOptions | 基础用户选项类型,包含 drain、enrich、keep、include、exclude、routes |
MiddlewareLoggerOptions | 内部选项,在 BaseEvlogOptions 基础上扩展了 method、path、requestId、headers |
MiddlewareLoggerResult | 返回类型:{ logger, finish, skipped } |
extractSafeHeaders(headers) | 从 Web API 的 Headers 对象中过滤敏感头部(适用于 Hono、Elysia、Deno、Bun) |
extractSafeNodeHeaders(headers) | 从 Node.js 的 IncomingHttpHeaders 中过滤敏感头部(适用于 Express、Fastify、nestJS) |
createLoggerStorage(hint) | 返回 { storage, useLogger } 的工厂函数,基于 AsyncLocalStorage |
extractErrorStatus(error) | 从任意错误对象中提取 HTTP 状态码(支持 status 或 statusCode 字段) |
shouldLog(path, include, exclude) | 路由过滤逻辑(支持通配符模式) |
getServiceForPath(path, routes) | 根据路径解析对应的服务名称 |
RequestLogger、DrainContext、EnrichContext、WideEvent、TailSamplingContext 等类型可从主包 evlog 中导出。
架构
每个 evlog 框架集成都遵循相同的 5 步模式:
请求 → createMiddlewareLogger() → 存储日志器 → 处理请求 → finish()
- 提取
method、path、requestId和headers,从框架请求对象中获取 - 调用
createMiddlewareLogger(),传入这些字段以及用户选项 - 检查
skipped—— 若为true,表示路由被过滤,跳过后续中间件 - 存储
logger到框架的上下文(如req.log、c.set('log')等) - 调用
finish({ status })(成功)或finish({ error })(失败),处理发送、增强与排水
createMiddlewareLogger 负责其余所有工作:路由过滤、服务覆盖、耗时统计、尾部采样、事件发送、数据增强与排水。
最小示例
以下是一个适用于通用 Node.js HTTP 框架的完整集成:
my-framework-evlog.ts
import type { IncomingMessage, ServerResponse } from 'node:http'
import type { RequestLogger } from 'evlog'
import {
createMiddlewareLogger,
extractSafeNodeHeaders,
createLoggerStorage,
type BaseEvlogOptions,
} from 'evlog/toolkit'
export type MyFrameworkEvlogOptions = BaseEvlogOptions
const { storage, useLogger } = createLoggerStorage(
'中间件上下文。确保在路由注册之前挂载 evlog 中间件。',
)
export { useLogger }
export function evlog(options: MyFrameworkEvlogOptions = {}) {
return async (req: IncomingMessage, res: ServerResponse, next: () => Promise<void>) => {
const { logger, finish, skipped } = createMiddlewareLogger({
method: req.method || 'GET',
path: req.url || '/',
requestId: (req.headers['x-request-id'] as string) || crypto.randomUUID(),
headers: extractSafeNodeHeaders(req.headers),
...options,
})
if (skipped) {
await next()
return
}
;(req as IncomingMessage & { log: RequestLogger }).log = logger
try {
await storage.run(logger, () => next())
await finish({ status: res.statusCode })
} catch (error) {
await finish({ error: error as Error })
throw error
}
}
}
仅此而已。该中间件将免费获得所有功能:路由过滤、排水适配器、数据增强、尾部采样、错误捕获与耗时统计。
关键规则
- 始终使用
createMiddlewareLogger—— 不要直接调用createRequestLogger - 使用正确的头部提取器 ——
extractSafeHeaders用于 Web API 的Headers(Hono、Elysia、Deno),extractSafeNodeHeaders用于 Node.js 的IncomingHttpHeaders(Express、Fastify) - 展开用户选项 ——
...options会自动将drain、enrich、keep、include、exclude传递给管道 - 在成功和错误路径中都调用
finish()—— 它会处理发送、增强与排水 - 重新抛出错误,以确保框架的错误处理器仍能生效
- 导出
useLogger()—— 消费者需要它来从服务函数中访问日志器 - 导出扩展
BaseEvlogOptions的选项类型 —— 为 IDE 提供drain、enrich、keep的自动补全
使用方式
构建完成后,你的集成可以像其他集成一样使用:
src/index.ts
import { initLogger } from 'evlog'
import { evlog, useLogger } from './my-framework-evlog'
import { createAxiomDrain } from 'evlog/axiom'
initLogger({ env: { service: 'my-api' } })
app.use(evlog({
include: ['/api/**'],
drain: createAxiomDrain(),
enrich: (ctx) => {
ctx.event.region = process.env.FLY_REGION
},
keep: (ctx) => {
if (ctx.duration && ctx.duration > 2000) ctx.shouldKeep = true
},
}))
app.get('/api/users', (req, res) => {
req.log.set({ users: { count: 42 } })
res.json({ users: [] })
})
// 从调用栈中的任意位置访问日志器
function findUsers() {
const log = useLogger()
log.set({ db: { query: 'SELECT * FROM users' } })
}
参考实现
研究以下内置集成,了解框架相关的特定模式:
| 框架 | 行数 | 模式 | 源码 |
|---|---|---|---|
| Hono | ~40 | Web API 头部提取、c.set()、try/catch | hono/index.ts |
| Express | ~60 | Node.js 头部、req.log、res.on('finish') | express/index.ts |
| Elysia | ~70 | 插件 API、derive()、onAfterHandle/onError | elysia/index.ts |
| Fastify | ~70 | 插件、decorateRequest、onRequest/onResponse 钩子 | fastify/index.ts |
为尚未支持的框架编写了集成?提交 PR —— 社区会感谢你的。