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

OpenTelemetry Next.js:http_server_duration指标缺失http_route标签

在Next.js OpenTelemetry中为http_server_duration指标添加http_route标签

问题背景

我在Next.js应用中基于OpenTelemetry实现了追踪与指标功能,数据通过Grafana Agent转发至Tempo(追踪)和Prometheus(指标)。目前Prometheus中能获取到http_server_duration_*系列指标,但这些指标缺少http_route标签;而追踪数据的Span属性里能看到http.target和http.url,且我的应用未使用Express(Express的OpenTelemetry Instrumentation会自动为Span和指标添加http_route)。

问题解答

1. 能否通过requestHook为Span设置属性,让http_server_duration_*指标带上http_route标签?

可以实现,但需要同时配置Span属性注入和指标维度提取规则,你之前的代码仅设置了Span属性但未配置指标提取该属性作为标签。

修改后的配置代码如下:

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { PeriodicExportingMetricReader, ConsoleMetricExporter } = require('@opentelemetry/sdk-metrics');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter(),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter(),
  }),
  instrumentations: [
    getNodeAutoInstrumentations({
      '@opentelemetry/instrumentation-fs': {
        enabled: false,
      },
      '@opentelemetry/instrumentation-http': {
        requestHook: (span, request) => {
          span.updateName(`${request.method} ${request.url || request.path}`);
          // 提取纯净路由(去掉查询参数)
          const route = new URL(request.url, 'http://localhost').pathname;
          span.setAttribute('http.route', route);
        },
        // 配置指标提取http.route作为标签维度
        metricAttributes: {
          enabled: true,
          attributes: ['http.route', 'http.method', 'http.status_code']
        }
      },
    }),
  ]
});

sdk.start();

关键说明:

  • 在requestHook中,通过new URL解析出不含查询参数的纯净路由,设置为Span的http.route属性;
  • 通过metricAttributes配置,指定HTTP instrumentation需要将http.route作为指标标签维度,这样http_server_duration_*指标就会自动带上该标签。

2. 替代方案

如果上述方法不生效,可尝试以下方案:

方案一:自定义OpenTelemetry View

通过创建自定义View,显式修改http.server.duration指标的维度,强制添加http.route标签:

const { View } = require('@opentelemetry/sdk-metrics');

// 自定义View
const httpDurationView = new View({
  instrumentName: 'http.server.duration',
  aggregation: undefined, // 保留原有聚合方式
  attributeFilter: (attributes) => {
    // 确保http.route存在,若不存在可从http.target提取
    if (!attributes['http.route'] && attributes['http.target']) {
      attributes['http.route'] = new URL(attributes['http.target'], 'http://localhost').pathname;
    }
    return attributes;
  },
});

// 在NodeSDK中添加views配置
const sdk = new NodeSDK({
  // ... 其他配置
  views: [httpDurationView],
  // ... 其他配置
});

方案二:Grafana Agent侧Relabel规则

在Grafana Agent的Prometheus配置中,添加relabel规则,从http_target或http_url中提取路由并添加为http_route标签:

scrape_configs:
  - job_name: 'nextjs-app'
    # ... 其他抓取配置
    relabel_configs:
      - source_labels: [http_target]
        regex: '^(/[^?]+)'
        target_label: http_route
        replacement: '$1'

方案三:Next.js中间件注入路由

在Next.js的middleware.ts中,为请求添加路由上下文,再在OpenTelemetry的requestHook中读取:

// middleware.ts
export function middleware(request: NextRequest) {
  request.headers.set('x-http-route', new URL(request.url).pathname);
}

然后在OpenTelemetry配置中读取该头信息:

requestHook: (span, request) => {
  const route = request.headers['x-http-route'];
  span.setAttribute('http.route', route);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:38:11