← 中文资源

简体中文版本

Fastify Pino 结构化请求日志

为 Fastify 接入 Pino 结构化日志:请求 ID 生成、敏感头脱敏、响应序列化与慢请求钩子告警一应俱全。

阅读英文原文

示例说明

日志的价值取决于能否被检索与关联。Fastify 内建 Pino 集成,每个请求自动携带上下文日志对象;genReqId 让上游网关的请求 ID 透传贯穿全链路;redact 在日志落地前擦除授权头与密码字段,避免审计事故。onResponse 钩子基于耗时阈值输出慢请求告警,是低成本的性能哨兵。

技术要点

  • genReqId 复用上游请求头或生成 UUID
  • redact 配置拦截敏感字段写入
  • elapsedTime 支撑慢请求阈值告警

代码解读

构造 Fastify 实例时传入 logger 配置对象,level 从环境变量读取并默认 info;serializers 自定义响应日志只保留状态码与耗时,避免序列化整个响应体。onResponse 钩子在响应完成后判断耗时超过 1 秒即以 warn 级别记录目标 URL。

使用建议

生产环境应输出 JSON 到 stdout 由采集器接管,pino-pretty 仅用于本地开发。redact 路径要随新增敏感字段同步维护。请求 ID 应最终回写到响应头,方便用户报障时定位。

代码示例

import Fastify from 'fastify';

const app = Fastify({
  logger: {
    level: process.env.LOG_LEVEL ?? 'info',
    genReqId: (req) => req.headers['x-request-id'] ?? crypto.randomUUID(),
    redact: {
      paths: ['req.headers.authorization', 'req.headers.cookie', '*.password'],
      censor: '[REDACTED]',
    },
    serializers: {
      res(reply) {
        return { statusCode: reply.statusCode, responseTime: reply.elapsedTime };
      },
    },
    transport: { target: 'pino-pretty', options: { colorize: true } },
  },
});

app.addHook('onResponse', async (request, reply) => {
  if (reply.elapsedTime > 1000) {
    request.log.warn({ url: request.url }, 'slow request');
  }
});

app.get('/health', async () => ({ status: 'ok' }));

await app.listen({ port: 3000, host: '0.0.0.0' });