diff options
Diffstat (limited to 'packages/core/src/telemetry/metrics.ts')
| -rw-r--r-- | packages/core/src/telemetry/metrics.ts | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/packages/core/src/telemetry/metrics.ts b/packages/core/src/telemetry/metrics.ts new file mode 100644 index 00000000..2e6bd909 --- /dev/null +++ b/packages/core/src/telemetry/metrics.ts @@ -0,0 +1,145 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + metrics, + Attributes, + ValueType, + Meter, + Counter, + Histogram, +} from '@opentelemetry/api'; +import { + SERVICE_NAME, + METRIC_TOOL_CALL_COUNT, + METRIC_TOOL_CALL_LATENCY, + METRIC_API_REQUEST_COUNT, + METRIC_API_REQUEST_LATENCY, + METRIC_TOKEN_INPUT_COUNT, + METRIC_SESSION_COUNT, +} from './constants.js'; + +let cliMeter: Meter | undefined; +let toolCallCounter: Counter | undefined; +let toolCallLatencyHistogram: Histogram | undefined; +let apiRequestCounter: Counter | undefined; +let apiRequestLatencyHistogram: Histogram | undefined; +let tokenInputCounter: Counter | undefined; +let isMetricsInitialized = false; + +export function getMeter(): Meter | undefined { + if (!cliMeter) { + cliMeter = metrics.getMeter(SERVICE_NAME); + } + return cliMeter; +} + +export function initializeMetrics(): void { + if (isMetricsInitialized) return; + + const meter = getMeter(); + if (!meter) return; + + toolCallCounter = meter.createCounter(METRIC_TOOL_CALL_COUNT, { + description: 'Counts tool calls, tagged by function name and success.', + valueType: ValueType.INT, + }); + toolCallLatencyHistogram = meter.createHistogram(METRIC_TOOL_CALL_LATENCY, { + description: 'Latency of tool calls in milliseconds.', + unit: 'ms', + valueType: ValueType.INT, + }); + apiRequestCounter = meter.createCounter(METRIC_API_REQUEST_COUNT, { + description: 'Counts API requests, tagged by model and status.', + valueType: ValueType.INT, + }); + apiRequestLatencyHistogram = meter.createHistogram( + METRIC_API_REQUEST_LATENCY, + { + description: 'Latency of API requests in milliseconds.', + unit: 'ms', + valueType: ValueType.INT, + }, + ); + tokenInputCounter = meter.createCounter(METRIC_TOKEN_INPUT_COUNT, { + description: 'Counts the total number of input tokens sent to the API.', + valueType: ValueType.INT, + }); + + const sessionCounter = meter.createCounter(METRIC_SESSION_COUNT, { + description: 'Count of CLI sessions started.', + valueType: ValueType.INT, + }); + sessionCounter.add(1); + isMetricsInitialized = true; +} + +export function recordToolCallMetrics( + functionName: string, + durationMs: number, + success: boolean, +): void { + if (!toolCallCounter || !toolCallLatencyHistogram || !isMetricsInitialized) + return; + + const metricAttributes: Attributes = { + function_name: functionName, + success, + }; + toolCallCounter.add(1, metricAttributes); + toolCallLatencyHistogram.record(durationMs, { + function_name: functionName, + }); +} + +export function recordApiRequestMetrics( + model: string, + inputTokenCount: number, +): void { + if (!tokenInputCounter || !isMetricsInitialized) return; + tokenInputCounter.add(inputTokenCount, { model }); +} + +export function recordApiResponseMetrics( + model: string, + durationMs: number, + statusCode?: number | string, + error?: string, +): void { + if ( + !apiRequestCounter || + !apiRequestLatencyHistogram || + !isMetricsInitialized + ) + return; + const metricAttributes: Attributes = { + model, + status_code: statusCode ?? (error ? 'error' : 'ok'), + }; + apiRequestCounter.add(1, metricAttributes); + apiRequestLatencyHistogram.record(durationMs, { model }); +} + +export function recordApiErrorMetrics( + model: string, + durationMs: number, + statusCode?: number | string, + errorType?: string, +): void { + if ( + !apiRequestCounter || + !apiRequestLatencyHistogram || + !isMetricsInitialized + ) + return; + const metricAttributes: Attributes = { + model, + status_code: statusCode ?? 'error', + error_type: errorType ?? 'unknown', + }; + apiRequestCounter.add(1, metricAttributes); + apiRequestLatencyHistogram.record(durationMs, { model }); +} |
