diff --git a/extensions/copilot/src/platform/otel/node/otelServiceImpl.ts b/extensions/copilot/src/platform/otel/node/otelServiceImpl.ts index 2ab17ec5f7b..226f59c8ea7 100644 --- a/extensions/copilot/src/platform/otel/node/otelServiceImpl.ts +++ b/extensions/copilot/src/platform/otel/node/otelServiceImpl.ts @@ -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 = 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>(); private readonly _counters = new Map>(); @@ -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);