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

如何为OpenTelemetry SDK生成的指标添加Exemplars?

问题描述

我正在尝试为基于JavaScript的API生成的指标添加Exemplars,目前使用OpenTelemetry JS API和SDK做代码埋点。

我的计数器代码如下:

/**
 * Using a counter to measure the total number of posts received by the API
 */
exports.postCount = apiMeter.createCounter('api.posts.count.total', {
    description: "Total number of posts received",
    unit: "posts"
});

我会在特定条件下递增计数器:

// inside the condition
postCount.add(1)

我曾尝试把Trace Context作为标签添加,像这样:

postCount.add(1, {trace_id: xxxxeeia});

但后来发现这种方式不正确,请问如何通过OpenTelemetry API正确添加Exemplars?

补充的指标导出器配置:

// Metrics
const metricExporter = new OTLPMetricExporter({url: `${OTEL_ENDPOINT}/v1/metrics`});
const meterProvider = new MeterProvider({
    resource: resource.merge(serviceResource),
});

meterProvider.addMetricReader(new PeriodicExportingMetricReader({
    exporter: metricExporter,
    exportIntervalMillis: 1000,
}));  

以及读取指标值的方式:

app.use((req, res, next) => {
    // Increment the counter when the response finishes, so to get the proper status code
    res.on('close', () => {
        requestCounter.add(1, { "http.method": req.method, "req.path": req.path, "res.status": res.statusCode });
    });
    next();
});

解决方案

在OpenTelemetry JS SDK中,Exemplars不能直接作为普通标签传入,需要通过add方法的第三个参数(可选配置对象)来设置,且需确保当前上下文存在有效的Trace Context(即请求已被链路追踪覆盖)。

1. 确认Trace Context已生效

先确保API已配置OpenTelemetry TraceProvider,且请求链路已被正确追踪——可以通过@opentelemetry/instrumentation-express这类自动埋点工具,或者手动创建Span实现。只有当前上下文存在活跃Span时,才能获取到可用的trace_id和span_id用于生成Exemplars。

2. 修改计数器递增逻辑

调用add方法时,在第三个参数中传入exemplars配置。通过trace.getSpan(context.active())获取当前活跃Span,再提取其traceId和spanId:

const { trace, context } = require('@opentelemetry/api');

// 在需要递增计数器的位置
const activeSpan = trace.getSpan(context.active());
if (activeSpan) {
    const spanContext = activeSpan.spanContext();
    postCount.add(1, 
        // 原有的标签集合
        { "http.method": req.method, "req.path": req.path, "res.status": res.statusCode },
        // Exemplars配置
        {
            exemplars: [
                {
                    traceId: spanContext.traceId,
                    spanId: spanContext.spanId,
                    // 可选:添加额外属性到Exemplar
                    attributes: {
                        "user.id": req.user?.id
                    }
                }
            ]
        }
    );
} else {
    // 无活跃Span时正常递增计数器
    postCount.add(1, { "http.method": req.method, "req.path": req.path, "res.status": res.statusCode });
}

3. 适配你的请求计数器示例

把你提供的requestCounter递增代码修改为:

const { trace, context } = require('@opentelemetry/api');

app.use((req, res, next) => {
    res.on('close', () => {
        const attributes = { "http.method": req.method, "req.path": req.path, "res.status": res.statusCode };
        const activeSpan = trace.getSpan(context.active());
        
        if (activeSpan) {
            const spanContext = activeSpan.spanContext();
            requestCounter.add(1, attributes, {
                exemplars: [{
                    traceId: spanContext.traceId,
                    spanId: spanContext.spanId
                }]
            });
        } else {
            requestCounter.add(1, attributes);
        }
    });
    next();
});

注意事项

  • 确保使用的OpenTelemetry JS API和SDK版本一致(建议SDK >=1.8.0),避免兼容性问题。
  • 后端存储需支持Exemplars(如Prometheus >=2.37.0、OpenTelemetry Collector),否则Exemplars会被忽略。
  • Exemplars仅会关联到标签基数较低的时间序列指标,过高基数的指标可能无法正常采集Exemplars。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:05:32