如何为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
相关产品推荐
相关产品推荐

