diff --git a/src/main.ts b/src/main.ts index a8fa9bbbf..8ff4f8136 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,6 +18,7 @@ import {McpResponse} from './McpResponse.js'; import {Mutex} from './Mutex.js'; import {ClearcutLogger} from './telemetry/clearcut-logger.js'; import {computeFlagUsage} from './telemetry/flag-utils.js'; +import {bucketizeLatency} from './telemetry/metric-utils.js'; import { McpServer, StdioServerTransport, @@ -221,7 +222,7 @@ function registerTool(tool: ToolDefinition): void { void clearcutLogger?.logToolInvocation({ toolName: tool.name, success, - latencyMs: Date.now() - startTime, + latencyMs: bucketizeLatency(Date.now() - startTime), }); guard.dispose(); } diff --git a/src/telemetry/metric-utils.ts b/src/telemetry/metric-utils.ts new file mode 100644 index 000000000..55e834f41 --- /dev/null +++ b/src/telemetry/metric-utils.ts @@ -0,0 +1,16 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +const LATENCY_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000]; + +export function bucketizeLatency(latencyMs: number): number { + for (const bucket of LATENCY_BUCKETS) { + if (latencyMs <= bucket) { + return bucket; + } + } + return LATENCY_BUCKETS[LATENCY_BUCKETS.length - 1]; +} diff --git a/tests/telemetry/metric-utils.test.ts b/tests/telemetry/metric-utils.test.ts new file mode 100644 index 000000000..789594f3c --- /dev/null +++ b/tests/telemetry/metric-utils.test.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'node:assert'; +import {describe, it} from 'node:test'; + +import {bucketizeLatency} from '../../src/telemetry/metric-utils.js'; + +describe('bucketizeLatency', () => { + it('should bucketize values correctly', () => { + assert.strictEqual(bucketizeLatency(0), 50); + assert.strictEqual(bucketizeLatency(25), 50); + assert.strictEqual(bucketizeLatency(50), 50); + + assert.strictEqual(bucketizeLatency(51), 100); + assert.strictEqual(bucketizeLatency(100), 100); + + assert.strictEqual(bucketizeLatency(101), 250); + assert.strictEqual(bucketizeLatency(250), 250); + + assert.strictEqual(bucketizeLatency(499), 500); + assert.strictEqual(bucketizeLatency(500), 500); + + assert.strictEqual(bucketizeLatency(900), 1000); + assert.strictEqual(bucketizeLatency(1000), 1000); + + assert.strictEqual(bucketizeLatency(2000), 2500); + assert.strictEqual(bucketizeLatency(2500), 2500); + + assert.strictEqual(bucketizeLatency(4000), 5000); + assert.strictEqual(bucketizeLatency(5000), 5000); + + assert.strictEqual(bucketizeLatency(6000), 10000); + assert.strictEqual(bucketizeLatency(10000), 10000); + + assert.strictEqual(bucketizeLatency(10001), 10000); + assert.strictEqual(bucketizeLatency(99999), 10000); + }); +});