Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/otel/common/test/genAiMetrics.spec.ts
13406 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { describe, expect, it, vi } from 'vitest';
7
import { Event } from '../../../../util/vs/base/common/event';
8
import { GenAiAttr, GenAiOperationName, GenAiProviderName, GenAiTokenType, StdAttr } from '../genAiAttributes';
9
import { GenAiMetrics } from '../genAiMetrics';
10
import { resolveOTelConfig } from '../otelConfig';
11
import type { IOTelService } from '../otelService';
12
13
function createMockOTelService(): IOTelService & { recordMetric: ReturnType<typeof vi.fn>; incrementCounter: ReturnType<typeof vi.fn> } {
14
const config = resolveOTelConfig({ env: {}, extensionVersion: '1.0.0', sessionId: 'test' });
15
return {
16
_serviceBrand: undefined!,
17
config,
18
startSpan: vi.fn(),
19
startActiveSpan: vi.fn(),
20
getActiveTraceContext: vi.fn(),
21
storeTraceContext: vi.fn(),
22
getStoredTraceContext: vi.fn(),
23
runWithTraceContext: vi.fn((_ctx: any, fn: any) => fn()),
24
recordMetric: vi.fn(),
25
incrementCounter: vi.fn(),
26
emitLogRecord: vi.fn(),
27
flush: vi.fn(),
28
shutdown: vi.fn(),
29
injectCompletedSpan: vi.fn(),
30
onDidCompleteSpan: Event.None,
31
onDidEmitSpanEvent: Event.None,
32
};
33
}
34
35
describe('GenAiMetrics', () => {
36
it('recordOperationDuration calls recordMetric with correct attributes', () => {
37
const otel = createMockOTelService();
38
39
GenAiMetrics.recordOperationDuration(otel, 1.5, {
40
operationName: GenAiOperationName.CHAT,
41
providerName: GenAiProviderName.OPENAI,
42
requestModel: 'gpt-4o',
43
responseModel: 'gpt-4o-2024-05-13',
44
serverAddress: 'api.copilot.com',
45
errorType: 'timeout',
46
});
47
48
expect(otel.recordMetric).toHaveBeenCalledWith('gen_ai.client.operation.duration', 1.5, {
49
[GenAiAttr.OPERATION_NAME]: 'chat',
50
[GenAiAttr.PROVIDER_NAME]: 'openai',
51
[GenAiAttr.REQUEST_MODEL]: 'gpt-4o',
52
[GenAiAttr.RESPONSE_MODEL]: 'gpt-4o-2024-05-13',
53
[StdAttr.SERVER_ADDRESS]: 'api.copilot.com',
54
[StdAttr.ERROR_TYPE]: 'timeout',
55
});
56
});
57
58
it('recordTokenUsage calls recordMetric with token type', () => {
59
const otel = createMockOTelService();
60
61
GenAiMetrics.recordTokenUsage(otel, 1000, 'input', {
62
operationName: GenAiOperationName.CHAT,
63
providerName: GenAiProviderName.OPENAI,
64
requestModel: 'gpt-4o',
65
});
66
67
expect(otel.recordMetric).toHaveBeenCalledWith('gen_ai.client.token.usage', 1000, {
68
[GenAiAttr.OPERATION_NAME]: 'chat',
69
[GenAiAttr.PROVIDER_NAME]: 'openai',
70
[GenAiAttr.TOKEN_TYPE]: GenAiTokenType.INPUT,
71
[GenAiAttr.REQUEST_MODEL]: 'gpt-4o',
72
});
73
});
74
75
it('recordToolCallCount increments counter', () => {
76
const otel = createMockOTelService();
77
78
GenAiMetrics.recordToolCallCount(otel, 'readFile', true);
79
80
expect(otel.incrementCounter).toHaveBeenCalledWith('copilot_chat.tool.call.count', 1, {
81
[GenAiAttr.TOOL_NAME]: 'readFile',
82
success: true,
83
});
84
});
85
86
it('recordToolCallDuration records histogram', () => {
87
const otel = createMockOTelService();
88
89
GenAiMetrics.recordToolCallDuration(otel, 'runCommand', 500);
90
91
expect(otel.recordMetric).toHaveBeenCalledWith('copilot_chat.tool.call.duration', 500, {
92
[GenAiAttr.TOOL_NAME]: 'runCommand',
93
});
94
});
95
96
it('recordAgentDuration records histogram', () => {
97
const otel = createMockOTelService();
98
99
GenAiMetrics.recordAgentDuration(otel, 'copilot', 15.2);
100
101
expect(otel.recordMetric).toHaveBeenCalledWith('copilot_chat.agent.invocation.duration', 15.2, {
102
[GenAiAttr.AGENT_NAME]: 'copilot',
103
});
104
});
105
106
it('incrementSessionCount increments counter', () => {
107
const otel = createMockOTelService();
108
109
GenAiMetrics.incrementSessionCount(otel);
110
111
expect(otel.incrementCounter).toHaveBeenCalledWith('copilot_chat.session.count');
112
});
113
114
it('omits optional attributes when not provided', () => {
115
const otel = createMockOTelService();
116
117
GenAiMetrics.recordOperationDuration(otel, 0.5, {
118
operationName: GenAiOperationName.CHAT,
119
providerName: GenAiProviderName.OPENAI,
120
requestModel: 'gpt-4o',
121
});
122
123
const attrs = otel.recordMetric.mock.calls[0][2];
124
expect(attrs).not.toHaveProperty(GenAiAttr.RESPONSE_MODEL);
125
expect(attrs).not.toHaveProperty(StdAttr.SERVER_ADDRESS);
126
expect(attrs).not.toHaveProperty(StdAttr.ERROR_TYPE);
127
});
128
});
129
130