Merge pull request #312244 from microsoft/zhichli/otelfix1

fix: use GenAI semconv explicit bucket boundaries for OTEL histograms
This commit is contained in:
Zhichao Li
2026-04-23 16:26:13 -07:00
committed by GitHub

View File

@@ -9,7 +9,7 @@ import type { OTelConfig } from '../common/otelConfig';
import { type ICompletedSpanData, type IOTelService, type ISpanEventData, type ISpanEventRecord, type ISpanHandle, SpanKind, type SpanOptions, SpanStatusCode, type TraceContext } from '../common/otelService';
// Type-only imports — erased by esbuild, zero bundle impact
import type { Attributes, Context, Meter, Span, SpanContext, Tracer } from '@opentelemetry/api';
import type { Attributes, Context, Meter, MetricOptions, Span, SpanContext, Tracer } from '@opentelemetry/api';
import type { AnyValueMap, Logger } from '@opentelemetry/api-logs';
import type { ExportResult } from '@opentelemetry/core';
import type { BatchLogRecordProcessor, LogRecordExporter } from '@opentelemetry/sdk-logs';
@@ -435,6 +435,15 @@ export class NodeOTelService implements IOTelService {
// ── Metric API ──
/**
* Explicit bucket boundaries per the OTel GenAI semantic conventions.
* @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/
*/
private static readonly _histogramOptions: ReadonlyMap<string, MetricOptions> = new Map([
['gen_ai.client.operation.duration', { advice: { explicitBucketBoundaries: [0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, 20.48, 40.96, 81.92] } }],
['gen_ai.client.token.usage', { advice: { explicitBucketBoundaries: [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864] } }],
]);
private readonly _histograms = new Map<string, ReturnType<Meter['createHistogram']>>();
private readonly _counters = new Map<string, ReturnType<Meter['createCounter']>>();
@@ -447,7 +456,7 @@ export class NodeOTelService implements IOTelService {
}
let histogram = this._histograms.get(name);
if (!histogram) {
histogram = this._meter.createHistogram(name);
histogram = this._meter.createHistogram(name, NodeOTelService._histogramOptions.get(name));
this._histograms.set(name, histogram);
}
histogram.record(value, attributes);