You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 12.x如何通过请求头传递correlationId实现Pino日志关联?

Next.js 12.x 结合 Pino 实现带 Correlation ID 的服务端日志

核心思路

靠 Next.js 12 的 middleware.ts 统一处理 Correlation ID,用Cookie把ID传递到服务端数据获取方法(getServerSideProps/getStaticProps),再封装 Pino 实例,让它自动把这个ID注入到每条日志里,不用每次手动加。

1. 完善 Middleware 的 Correlation ID 处理

在 middleware.ts 里,先检查请求头的correlation-id,没有的话生成一个UUID,然后把ID写入Cookie,同时回写到响应头方便客户端后续请求携带:

import { NextRequest, NextResponse } from 'next/server';
import { v4 as uuidv4 } from 'uuid';

export function middleware(req: NextRequest) {
  // 从请求头取ID,没有就生成新的
  const correlationId = req.headers.get('correlation-id') || uuidv4();
  
  const res = NextResponse.next();
  // 写入Cookie,服务端方法能通过req.cookies读取
  res.cookies.set('correlation-id', correlationId, {
    httpOnly: true,
    sameSite: 'strict',
    path: '/',
  });
  // 回写响应头,方便客户端后续请求带上这个ID
  res.headers.set('correlation-id', correlationId);
  
  return res;
}

// 匹配所有路由,确保每个请求都经过处理
export const config = {
  matcher: '/:path*',
};

2. 封装 Pino 日志实例,自动带 Correlation ID

新建一个logger.ts文件,封装Pino,让它能从Cookie或传入的ID自动生成带关联ID的日志实例:

import pino from 'pino';

// 基础Pino配置,适配Kibana的JSON格式
const baseLogger = pino({
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
  formatters: {
    level: (label) => ({ level: label.toUpperCase() }),
  },
  base: {
    service: '你的Next.js服务名',
  },
});

// 创建带Correlation ID的日志实例
export const createLogger = (correlationId?: string) => {
  return baseLogger.child({
    correlationId: correlationId || 'unknown',
  });
};

// 从请求的Cookie里提取Correlation ID的工具函数
export const getCorrelationIdFromReq = (req: { cookies: Record<string, string> }) => {
  return req.cookies['correlation-id'];
};

3. 在 getServerSideProps/getStaticProps 里用日志

在页面的服务端数据方法中,从context.req.cookies里取出ID,创建带ID的日志实例,之后打日志就会自动带上这个ID:

// pages/example.tsx
import { createLogger, getCorrelationIdFromReq } from '../utils/logger';

export async function getServerSideProps(context) {
  const correlationId = getCorrelationIdFromReq(context.req);
  const logger = createLogger(correlationId);
  
  logger.info('开始获取示例页面数据');
  // 业务逻辑...
  
  try {
    const data = await fetchSomeData();
    logger.debug('数据获取成功', { dataLength: data.length });
    return { props: { data } };
  } catch (err) {
    logger.error('数据获取失败', { error: err.message });
    return { props: { data: [] } };
  }
}

// getStaticProps 用法类似(注意:只有开启revalidate时,getStaticProps才会在服务端运行,此时能拿到请求Cookie;纯静态构建时没有请求上下文,ID会是'unknown')
export async function getStaticProps(context) {
  const correlationId = getCorrelationIdFromReq(context.req);
  const logger = createLogger(correlationId);
  
  logger.info('生成带revalidate的静态页面');
  // 业务逻辑...
  
  return { props: {}, revalidate: 60 };
}

4. API路由的日志增强(可选)

如果想让API路由也自动带上Correlation ID,可以写一个简单的wrapper:

// utils/apiWrapper.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { createLogger, getCorrelationIdFromReq } from './logger';

export const withLogger = (handler: (req: NextApiRequest, res: NextApiResponse, logger: pino.Logger) => Promise<void>) => {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    const correlationId = getCorrelationIdFromReq(req);
    const logger = createLogger(correlationId);
    
    try {
      await handler(req, res, logger);
    } catch (err) {
      logger.error('API处理失败', { error: err.message });
      res.status(500).json({ error: '服务器内部错误' });
    }
  };
};

用的时候直接套在API路由外面:

// pages/api/data.ts
import { withLogger } from '../../utils/apiWrapper';

export default withLogger(async (req, res, logger) => {
  logger.info('开始处理数据API请求');
  // 业务逻辑...
  res.status(200).json({ data: '示例数据' });
});

几个关键注意点

  • getStaticProps的特殊性:纯静态页面(无revalidate)的getStaticProps是在构建时执行的,此时没有请求上下文,Correlation ID会显示为unknown。如果需要构建时也有ID,可以在构建脚本里生成一个临时ID,或者忽略这类日志的ID。
  • Cookie安全性:设置httpOnly: true防止前端篡改,sameSite: 'strict'降低CSRF风险。
  • Kibana适配:确保Pino输出的是JSON格式日志,Kibana能直接解析correlationId字段,方便后续做链路追踪。

内容的提问来源于stack exchange,提问作者Matthew Trow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 01:00:59