Path: blob/main/extensions/copilot/src/platform/otel/common/otelService.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { createServiceIdentifier } from '../../../util/common/services';6import type { Event } from '../../../util/vs/base/common/event';7import type { OTelConfig } from './otelConfig';89export const IOTelService = createServiceIdentifier<IOTelService>('IOTelService');1011/**12* Serializable trace context for cross-boundary span propagation.13*/14export interface TraceContext {15readonly traceId: string;16readonly spanId: string;17/**18* W3C trace flags from the source span context (e.g. `0x01` for sampled). Optional19* because not all impls preserve it; consumers that build a W3C `traceparent` should20* fall back to a sampled value when unset.21*/22readonly traceFlags?: number;23/** W3C tracestate serialized as a comma-separated key=value list, when present. */24readonly traceState?: string;25}2627/**28* Abstracts the OpenTelemetry SDK so consumers don't import OTel directly.29* When disabled, all methods are no-ops with zero overhead.30*/31export interface IOTelService {32readonly _serviceBrand: undefined;33readonly config: OTelConfig;3435/**36* Start a new span. Returns a handle to set attributes and end the span.37* If OTel is disabled, returns a no-op handle.38*/39startSpan(name: string, options?: SpanOptions): ISpanHandle;4041/**42* Start a span and set it as active context so child spans are parented.43* Calls `fn` within the active span context.44*/45startActiveSpan<T>(name: string, options: SpanOptions, fn: (span: ISpanHandle) => Promise<T>): Promise<T>;4647/**48* Get the trace context (traceId + spanId) of the currently active span.49* Returns undefined if no span is active or OTel is disabled.50*/51getActiveTraceContext(): TraceContext | undefined;5253/**54* Store a trace context for later retrieval, keyed by a string ID.55* Used to propagate context across async boundaries (e.g., subagent invocations).56*/57storeTraceContext(key: string, context: TraceContext): void;5859/**60* Retrieve and remove a previously stored trace context by key.61*/62getStoredTraceContext(key: string): TraceContext | undefined;6364/**65* Run a function with a remote trace context set as active, without creating a span.66* Child spans created inside `fn` will be parented to the given trace context.67*/68runWithTraceContext<T>(traceContext: TraceContext, fn: () => Promise<T>): Promise<T>;6970/**71* Record a histogram metric value.72*/73recordMetric(name: string, value: number, attributes?: Record<string, string | number | boolean>): void;7475/**76* Increment a counter metric.77*/78incrementCounter(name: string, value?: number, attributes?: Record<string, string | number | boolean>): void;7980/**81* Emit an OTel log record / event.82*/83emitLogRecord(body: string, attributes?: Record<string, unknown>): void;8485/**86* Force flush all pending telemetry data.87*/88flush(): Promise<void>;8990/**91* Gracefully shut down the OTel SDK.92*/93shutdown(): Promise<void>;9495/**96* Inject an externally-created completed span into the OTel service's event stream.97* The span will fire `onDidCompleteSpan` (for the debug panel) but will NOT be98* exported via the OTLP exporter (the source system handles its own export).99*/100injectCompletedSpan(span: ICompletedSpanData): void;101102/**103* Fires when any span ends, providing a serializable snapshot of the span's data.104* Used by the debug panel to react to completed spans without depending on the OTel SDK.105*/106readonly onDidCompleteSpan: Event<ICompletedSpanData>;107108/**109* Fires synchronously when a span event is emitted via `ISpanHandle.addEvent()`.110* Enables real-time streaming of in-flight span events (e.g., user messages)111* without waiting for the span to complete.112*/113readonly onDidEmitSpanEvent: Event<ISpanEventData>;114}115116export const enum SpanKind {117INTERNAL = 0,118CLIENT = 2,119}120121export const enum SpanStatusCode {122UNSET = 0,123OK = 1,124ERROR = 2,125}126127export interface SpanOptions {128kind?: SpanKind;129attributes?: Record<string, string | number | boolean | string[]>;130/** When set, the span will be created as a child of this remote trace context. */131parentTraceContext?: TraceContext;132}133134/**135* Lightweight handle for a span, independent of the OTel SDK types.136*/137export interface ISpanHandle {138setAttribute(key: string, value: string | number | boolean | string[]): void;139setAttributes(attrs: Record<string, string | number | boolean | string[] | undefined>): void;140setStatus(code: SpanStatusCode, message?: string): void;141recordException(error: unknown): void;142/**143* Add a named event to this span with optional attributes.144* This fires `IOTelService.onDidEmitSpanEvent` synchronously.145*/146addEvent(name: string, attributes?: Record<string, string | number | boolean | string[]>): void;147/**148* Get the trace context (traceId + spanId) of this span.149* Used for cross-boundary propagation (e.g., linking subagent spans to their parent tool call).150*/151getSpanContext(): TraceContext | undefined;152end(): void;153}154155/**156* Shape of `modelOptions` passed through VS Code IPC for cross-process157* CapturingToken restoration and OTel trace context propagation.158*/159export interface OTelModelOptions {160readonly _capturingTokenCorrelationId?: string;161readonly _otelTraceContext?: TraceContext | null;162}163164/**165* Serializable snapshot of a completed span, fired via `IOTelService.onDidCompleteSpan`.166* Contains all in-memory attributes (including content attributes regardless of captureContent).167*/168export interface ICompletedSpanData {169readonly name: string;170readonly spanId: string;171readonly traceId: string;172readonly parentSpanId?: string;173readonly startTime: number; // milliseconds since epoch174readonly endTime: number; // milliseconds since epoch175readonly status: { readonly code: SpanStatusCode; readonly message?: string };176readonly attributes: Readonly<Record<string, string | number | boolean | string[]>>;177readonly events: readonly ISpanEventRecord[];178}179180/**181* A single event on a span (recorded via `ISpanHandle.addEvent`).182*/183export interface ISpanEventRecord {184readonly name: string;185readonly timestamp: number; // milliseconds since epoch186readonly attributes?: Readonly<Record<string, string | number | boolean | string[]>>;187}188189/**190* Data emitted via `IOTelService.onDidEmitSpanEvent` when a span event is added.191* Enables real-time streaming of in-flight span events to the debug panel.192*/193export interface ISpanEventData {194readonly spanId: string;195readonly traceId: string;196readonly parentSpanId?: string;197readonly eventName: string;198readonly attributes: Readonly<Record<string, string | number | boolean | string[]>>;199readonly timestamp: number; // milliseconds since epoch200}201202203