Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/telemetry/chatModelCountTelemetry.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 { Disposable } from '../../../../../base/common/lifecycle.js';
7
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
8
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../../common/contributions.js';
9
import { IChatService } from '../../common/chatService/chatService.js';
10
import { ChatAgentLocation } from '../../common/constants.js';
11
import { IChatWidgetService } from '../chat.js';
12
13
type ChatModelCountEvent = {
14
totalModels: number;
15
modelsOpenInWidgets: number;
16
backgroundModels: number;
17
backgroundModels_modifiedEditsKeepAlive: number;
18
backgroundModels_requestInProgressKeepAlive: number;
19
backgroundModels_otherHolders: number;
20
};
21
22
type ChatModelCountClassification = {
23
totalModels: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Total number of live chat models.' };
24
modelsOpenInWidgets: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of chat models that are open in a chat widget or editor.' };
25
backgroundModels: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of chat models with no open widget.' };
26
backgroundModels_modifiedEditsKeepAlive: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of background models held alive by the ChatModel#modifiedEditsKeepAlive reference (has pending edits).' };
27
backgroundModels_requestInProgressKeepAlive: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of background models held alive by the ChatModel#requestInProgressKeepAlive reference (request is running).' };
28
backgroundModels_otherHolders: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of background models with unrecognized holders (potential leaks).' };
29
};
30
31
type ChatModelsAtStartupClassification = ChatModelCountClassification & {
32
owner: 'roblourens';
33
comment: 'Tracks chat model counts at startup.';
34
};
35
36
type ChatModelCreatedEvent = ChatModelCountEvent & {
37
newModelLocation: string;
38
};
39
40
type ChatModelCreatedClassification = ChatModelCountClassification & {
41
newModelLocation: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The ChatAgentLocation of the newly created chat model.' };
42
owner: 'roblourens';
43
comment: 'Tracks chat model counts each time a new chat model is created, to detect accumulation of background sessions over the lifetime of a window.';
44
};
45
46
/**
47
* Logs telemetry about how many chat models are live at two moments:
48
* 1. At startup, after sessions with pending edits have been revived.
49
* 2. Each time a new chat model is created (skipping the very first one).
50
*
51
* Both events share the same model-count snapshot logic to track background
52
* session accumulation.
53
*/
54
export class ChatModelCountTelemetry extends Disposable implements IWorkbenchContribution {
55
56
static readonly ID = 'workbench.contrib.chatModelCountTelemetry';
57
58
constructor(
59
@IChatService private readonly chatService: IChatService,
60
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
61
@ITelemetryService private readonly telemetryService: ITelemetryService,
62
) {
63
super();
64
this.logStartupTelemetry();
65
this._register(this.chatService.onDidCreateModel(model => this.onDidCreateModel(model.initialLocation)));
66
}
67
68
private logStartupTelemetry(): void {
69
this.telemetryService.publicLog2<ChatModelCountEvent, ChatModelsAtStartupClassification>('chat.modelsAtStartup', this.getSnapshot());
70
}
71
72
private onDidCreateModel(newModelLocation: ChatAgentLocation): void {
73
const snapshot = this.getSnapshot();
74
75
// Skip the trivial case of the very first chat model in the window
76
if (snapshot.totalModels <= 1) {
77
return;
78
}
79
80
this.telemetryService.publicLog2<ChatModelCreatedEvent, ChatModelCreatedClassification>('chat.modelCreatedStats', {
81
...snapshot,
82
newModelLocation,
83
});
84
}
85
86
private getSnapshot(): ChatModelCountEvent {
87
const snapshot = this.chatService.getChatModelReferenceDebugInfo();
88
89
let modelsOpenInWidgets = 0;
90
let backgroundModels = 0;
91
let backgroundModels_modifiedEditsKeepAlive = 0;
92
let backgroundModels_requestInProgressKeepAlive = 0;
93
let backgroundModels_otherHolders = 0;
94
95
for (const model of snapshot.models) {
96
if (this.chatWidgetService.getWidgetBySessionResource(model.sessionResource)) {
97
modelsOpenInWidgets++;
98
} else {
99
backgroundModels++;
100
let hasOther = false;
101
for (const { holder } of model.holders) {
102
if (holder === 'ChatModel#modifiedEditsKeepAlive') {
103
backgroundModels_modifiedEditsKeepAlive++;
104
} else if (holder === 'ChatModel#requestInProgressKeepAlive') {
105
backgroundModels_requestInProgressKeepAlive++;
106
} else {
107
hasOther = true;
108
}
109
}
110
if (hasOther) {
111
backgroundModels_otherHolders++;
112
}
113
}
114
}
115
116
return {
117
totalModels: snapshot.totalModels,
118
modelsOpenInWidgets,
119
backgroundModels,
120
backgroundModels_modifiedEditsKeepAlive,
121
backgroundModels_requestInProgressKeepAlive,
122
backgroundModels_otherHolders,
123
};
124
}
125
}
126
127
registerWorkbenchContribution2(ChatModelCountTelemetry.ID, ChatModelCountTelemetry, WorkbenchPhase.AfterRestored);
128
129