如何在Next.js Edge运行时用@vercel/otel和register()监控中间件请求响应
Next.js Edge中间件全局追踪请求/响应方案
背景与约束
- Next.js 15.2+中,中间件默认运行在Edge Runtime,实验性Node.js Runtime不建议用于生产环境
- 使用
next dev --turbopack启动时,instrumentation.ts执行在nodejsRuntime,中间件执行在edgeRuntime - @vercel/otel是Edge Runtime唯一原生支持的OpenTelemetry方案,Node SDK完全不兼容Edge环境
实现步骤
1. 分Runtime初始化追踪逻辑
在instrumentation.ts中针对不同Runtime加载对应逻辑,避免跨环境错误:
import { trace } from '@opentelemetry/api'; import { NextResponse } from 'next/server'; export function register() { // Node Runtime:仅初始化Node SDK(用于非Edge服务端逻辑,可选) if (process.env.NEXT_RUNTIME === 'nodejs') { const { NodeSDK } = require('@opentelemetry/sdk-node'); const sdk = new NodeSDK({ serviceName: 'your-service-name', // 配置Collector地址与导出器 }); sdk.start(); } // Edge Runtime:扩展@vercel/otel实现中间件追踪 if (process.env.NEXT_RUNTIME === 'edge') { const { registerOTel } = require('@vercel/otel'); registerOTel({ serviceName: 'your-service-name', traceExporter: { type: 'otlp', url: 'http://localhost:4318/v1/traces', // 对应你的Collector地址 }, instrumentations: [ { name: 'custom-nextjs-middleware', setup() { // 拦截Request构造,捕获请求元数据 const OriginalRequest = globalThis.Request; globalThis.Request = class extends OriginalRequest { constructor(input, init) { super(input, init); const activeSpan = trace.getActiveSpan(); if (activeSpan) { activeSpan.setAttributes({ 'request.method': this.method, 'request.url': this.url, 'request.headers': JSON.stringify(Object.fromEntries(this.headers)), }); } } }; // 拦截NextResponse.next,捕获响应元数据 const originalNext = NextResponse.next; NextResponse.next = function (...args) { const response = originalNext.apply(this, args); const activeSpan = trace.getActiveSpan(); if (activeSpan) { activeSpan.setAttributes({ 'response.status': response.status, 'response.headers': JSON.stringify(Object.fromEntries(response.headers)), }); } return response; }; // 可按需扩展拦截NextResponse.redirect、rewrite等方法 }, }, ], }); } }
2. 配置Next.js钩子(兼容旧版本)
Next.js 15+无需额外配置,为兼容13.4-14版本,在next.config.js中添加:
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { instrumentationHook: true, }, }; module.exports = nextConfig;
3. 验证追踪效果
- 启动
opentelemetry-collector-dev-setup接收追踪数据 - 在任意中间件中添加调试代码,确认Span关联:
import { trace } from '@opentelemetry/api'; export function middleware(request) { const span = trace.getActiveSpan(); console.log('Current middleware span:', span?.spanContext()); return NextResponse.next(); }
- 查看Collector中的Span数据,确认每个中间件的请求/响应属性已被捕获
核心注意事项
- 禁止在Edge Runtime中导入Node SDK,会直接触发运行时错误
- 自定义插桩逻辑需保持原有API行为,仅追加追踪属性,避免破坏业务逻辑
- 生产环境需确保@vercel/otel版本与Next.js版本匹配,优先使用最新稳定版
内容的提问来源于stack exchange,提问作者Brendan Hoskins
相关产品推荐
相关产品推荐

