Skip to content

Commit e4091ab

Browse files
authored
Combine ProjectContext and RelatedFilesProvider Telemetry in One Event (#13157)
- This allows calculating the time spent on the extension side vs the language server side. - Also send filter telemetry if available.
1 parent c4d9f11 commit e4091ab

File tree

3 files changed

+97
-48
lines changed

3 files changed

+97
-48
lines changed

Diff for: Extension/src/LanguageServer/copilotProviders.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export async function registerRelatedFilesProvider(): Promise<void> {
4848
try {
4949
const getIncludesHandler = async () => (await getIncludes(uri, 1))?.includedFiles.map(file => vscode.Uri.file(file)) ?? [];
5050
const getTraitsHandler = async () => {
51-
const projectContext = await getProjectContext(uri, context);
51+
const projectContext = await getProjectContext(uri, context, telemetryProperties, telemetryMetrics);
5252

5353
if (!projectContext) {
5454
return undefined;

Diff for: Extension/src/LanguageServer/lmTool.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,20 @@ function filterCompilerArguments(compiler: string, compilerArguments: string[],
124124
if (filteredCompilerArguments.length > 0) {
125125
// Telemetry to learn about the argument distribution. The filtered arguments are expected to be non-PII.
126126
telemetryProperties["filteredCompilerArguments"] = filteredCompilerArguments.join(',');
127-
telemetryProperties["filters"] = Object.keys(filterMap).filter(filter => !!filter).join(',');
127+
}
128+
129+
const filters = Object.keys(filterMap).filter(filter => !!filter).join(',');
130+
if (filters) {
131+
telemetryProperties["filters"] = filters;
128132
}
129133

130134
return result;
131135
}
132136

133-
export async function getProjectContext(uri: vscode.Uri, context: { flags: Record<string, unknown> }): Promise<ProjectContext | undefined> {
134-
const telemetryProperties: Record<string, string> = {};
135-
const telemetryMetrics: Record<string, number> = {};
137+
export async function getProjectContext(uri: vscode.Uri, context: { flags: Record<string, unknown> }, telemetryProperties: Record<string, string>, telemetryMetrics: Record<string, number>): Promise<ProjectContext | undefined> {
136138
try {
137139
const projectContext = await checkDuration<ProjectContextResult | undefined>(async () => await getClients()?.ActiveClient?.getProjectContext(uri) ?? undefined);
138-
telemetryMetrics["duration"] = projectContext.duration;
140+
telemetryMetrics["projectContextDuration"] = projectContext.duration;
139141
if (!projectContext.result) {
140142
return undefined;
141143
}
@@ -186,10 +188,8 @@ export async function getProjectContext(uri: vscode.Uri, context: { flags: Recor
186188
catch {
187189
// Intentionally swallow any exception.
188190
}
189-
telemetryProperties["error"] = "true";
191+
telemetryProperties["projectContextError"] = "true";
190192
throw exception; // Throw the exception for auto-retry.
191-
} finally {
192-
telemetry.logCopilotEvent('ProjectContext', telemetryProperties, telemetryMetrics);
193193
}
194194
}
195195

Diff for: Extension/test/scenarios/SingleRootProject/tests/lmTool.test.ts

+88-39
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,17 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
179179
expectedCompiler,
180180
context,
181181
compilerArguments: compilerArguments,
182-
expectedCompilerArguments
182+
expectedCompilerArguments,
183+
telemetryProperties,
184+
telemetryMetrics
183185
}: {
184186
compiler: string;
185187
expectedCompiler: string;
186188
context: { flags: Record<string, unknown> };
187189
compilerArguments: string[];
188190
expectedCompilerArguments: Record<string, string>;
191+
telemetryProperties: Record<string, string>;
192+
telemetryMetrics: Record<string, number>;
189193
}) => {
190194
arrangeProjectContextFromCppTools({
191195
projectContextFromCppTools: {
@@ -200,7 +204,7 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
200204
}
201205
});
202206

203-
const result = await getProjectContext(mockTextDocumentStub.uri, context);
207+
const result = await getProjectContext(mockTextDocumentStub.uri, context, telemetryProperties, telemetryMetrics);
204208

205209
ok(result, 'result should not be undefined');
206210
ok(result.language === 'C++');
@@ -217,7 +221,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
217221
expectedCompiler: 'MSVC',
218222
context: { flags: { copilotcppMsvcCompilerArgumentFilter: '{"foo-?": ""}' } },
219223
compilerArguments: ['foo', 'bar', 'abc', 'foo-'],
220-
expectedCompilerArguments: { 'foo-?': 'foo-' }
224+
expectedCompilerArguments: { 'foo-?': 'foo-' },
225+
telemetryProperties: {},
226+
telemetryMetrics: {}
221227
});
222228
});
223229

@@ -227,7 +233,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
227233
expectedCompiler: 'Clang',
228234
context: { flags: { copilotcppClangCompilerArgumentFilter: '{"foo": "", "bar": ""}' } },
229235
compilerArguments: ['foo', 'bar', 'abc'],
230-
expectedCompilerArguments: { 'foo': 'foo', 'bar': 'bar' }
236+
expectedCompilerArguments: { 'foo': 'foo', 'bar': 'bar' },
237+
telemetryProperties: {},
238+
telemetryMetrics: {}
231239
});
232240
});
233241

@@ -237,7 +245,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
237245
expectedCompiler: 'Clang',
238246
context: { flags: { copilotcppClangCompilerArgumentFilter: '{"-std\\\\sc\\\\+\\\\+\\\\d+": ""}' } },
239247
compilerArguments: ['-std', 'c++17', '-std', 'foo', '-std', 'c++11', '-std', 'bar'],
240-
expectedCompilerArguments: { '-std\\sc\\+\\+\\d+': '-std c++11' }
248+
expectedCompilerArguments: { '-std\\sc\\+\\+\\d+': '-std c++11' },
249+
telemetryProperties: {},
250+
telemetryMetrics: {}
241251
});
242252
});
243253

@@ -247,7 +257,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
247257
expectedCompiler: 'GCC',
248258
context: { flags: { copilotcppGccCompilerArgumentFilter: '{"foo": "", "bar": ""}' } },
249259
compilerArguments: ['foo', 'bar', 'abc', 'bar', 'foo', 'bar'],
250-
expectedCompilerArguments: { 'foo': 'foo', 'bar': 'bar' }
260+
expectedCompilerArguments: { 'foo': 'foo', 'bar': 'bar' },
261+
telemetryProperties: {},
262+
telemetryMetrics: {}
251263
});
252264
});
253265

@@ -257,7 +269,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
257269
expectedCompiler: 'MSVC',
258270
context: { flags: { copilotcppMsvcCompilerArgumentFilter: '{"foo": "", "bar": ""}' } },
259271
compilerArguments: [],
260-
expectedCompilerArguments: {}
272+
expectedCompilerArguments: {},
273+
telemetryProperties: {},
274+
telemetryMetrics: {}
261275
});
262276
});
263277

@@ -267,7 +281,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
267281
expectedCompiler: 'GCC',
268282
context: { flags: {} },
269283
compilerArguments: ['foo', 'bar'],
270-
expectedCompilerArguments: {}
284+
expectedCompilerArguments: {},
285+
telemetryProperties: {},
286+
telemetryMetrics: {}
271287
});
272288
});
273289

@@ -277,7 +293,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
277293
expectedCompiler: 'MSVC',
278294
context: { flags: { copilotcppMsvcCompilerArgumentFilter: '{"": ""}' } },
279295
compilerArguments: ['foo', 'bar'],
280-
expectedCompilerArguments: {}
296+
expectedCompilerArguments: {},
297+
telemetryProperties: {},
298+
telemetryMetrics: {}
281299
});
282300
});
283301

@@ -291,7 +309,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
291309
}
292310
},
293311
compilerArguments: ['foo', 'bar'],
294-
expectedCompilerArguments: {}
312+
expectedCompilerArguments: {},
313+
telemetryProperties: {},
314+
telemetryMetrics: {}
295315
});
296316
});
297317

@@ -305,7 +325,9 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
305325
}
306326
},
307327
compilerArguments: ['foo', 'bar'],
308-
expectedCompilerArguments: {}
328+
expectedCompilerArguments: {},
329+
telemetryProperties: {},
330+
telemetryMetrics: {}
309331
});
310332
});
311333

@@ -321,33 +343,60 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
321343
}
322344
},
323345
compilerArguments: ['foo', 'bar'],
324-
expectedCompilerArguments: {}
346+
expectedCompilerArguments: {},
347+
telemetryProperties: {},
348+
telemetryMetrics: {}
325349
});
326350
});
327351

328352
it('should send telemetry.', async () => {
353+
const telemetryProperties: Record<string, string> = {};
354+
const telemetryMetrics: Record<string, number> = {};
329355
const input = {
330356
compiler: 'msvc',
331357
expectedCompiler: 'MSVC',
332358
context: { flags: { copilotcppMsvcCompilerArgumentFilter: '{"foo-?": "", "": "", "bar": "", "xyz": ""}' } },
333359
compilerArguments: ['foo', 'bar', 'foo-', 'abc'],
334-
expectedCompilerArguments: { 'foo-?': 'foo-', 'bar': 'bar' }
360+
expectedCompilerArguments: { 'foo-?': 'foo-', 'bar': 'bar' },
361+
telemetryProperties,
362+
telemetryMetrics
335363
};
336364
await testGetProjectContext(input);
337365

338-
ok(telemetryStub.calledOnce, 'Telemetry should be called once');
339-
ok(telemetryStub.calledWithMatch('ProjectContext', sinon.match({
340-
"language": 'C++',
341-
"compiler": input.expectedCompiler,
342-
"standardVersion": 'C++20',
343-
"targetPlatform": 'Windows',
344-
"targetArchitecture": 'x64',
345-
"filteredCompilerArguments": "foo,foo-,bar",
346-
"filters": "foo-?,bar,xyz"
347-
}), sinon.match({
348-
"compilerArgumentCount": input.compilerArguments.length,
349-
'duration': sinon.match.number
350-
})));
366+
ok(telemetryProperties['language'] === 'C++');
367+
ok(telemetryProperties['compiler'] === input.expectedCompiler);
368+
ok(telemetryProperties['standardVersion'] === 'C++20');
369+
ok(telemetryProperties['targetPlatform'] === 'Windows');
370+
ok(telemetryProperties['targetArchitecture'] === 'x64');
371+
ok(telemetryProperties['filteredCompilerArguments'] === 'foo,foo-,bar');
372+
ok(telemetryProperties['filters'] === 'foo-?,bar,xyz');
373+
ok(telemetryMetrics['compilerArgumentCount'] === input.compilerArguments.length);
374+
ok(telemetryMetrics['projectContextDuration'] !== undefined);
375+
});
376+
377+
it('should send filter telemetry if available.', async () => {
378+
const telemetryProperties: Record<string, string> = {};
379+
const telemetryMetrics: Record<string, number> = {};
380+
const input = {
381+
compiler: 'msvc',
382+
expectedCompiler: 'MSVC',
383+
context: { flags: { copilotcppMsvcCompilerArgumentFilter: '{"foo-?": "", "": "", "bar": "", "xyz": ""}' } },
384+
compilerArguments: ['abc'],
385+
expectedCompilerArguments: {},
386+
telemetryProperties,
387+
telemetryMetrics
388+
};
389+
await testGetProjectContext(input);
390+
391+
ok(telemetryProperties['language'] === 'C++');
392+
ok(telemetryProperties['compiler'] === input.expectedCompiler);
393+
ok(telemetryProperties['standardVersion'] === 'C++20');
394+
ok(telemetryProperties['targetPlatform'] === 'Windows');
395+
ok(telemetryProperties['targetArchitecture'] === 'x64');
396+
ok(telemetryProperties['filteredCompilerArguments'] === undefined);
397+
ok(telemetryProperties['filters'] === 'foo-?,bar,xyz');
398+
ok(telemetryMetrics['compilerArgumentCount'] === input.compilerArguments.length);
399+
ok(telemetryMetrics['projectContextDuration'] !== undefined);
351400
});
352401

353402
it('should not send telemetry for unknown values', async () => {
@@ -363,21 +412,21 @@ describe('CppConfigurationLanguageModelTool Tests', () => {
363412
}
364413
}
365414
});
415+
const telemetryProperties: Record<string, string> = {};
416+
const telemetryMetrics: Record<string, number> = {};
366417

367-
const result = await getProjectContext(mockTextDocumentStub.uri, { flags: {} });
418+
const result = await getProjectContext(mockTextDocumentStub.uri, {
419+
flags: { copilotcppMsvcCompilerArgumentFilter: '{"foo-?": "", "": "", "bar": "", "xyz": ""}' }
420+
}, telemetryProperties, telemetryMetrics);
368421

369-
ok(telemetryStub.calledOnce, 'Telemetry should be called once');
370-
ok(telemetryStub.calledWithMatch('ProjectContext', sinon.match({
371-
"targetArchitecture": 'bar'
372-
}), sinon.match({
373-
"compilerArgumentCount": 0
374-
})));
375-
ok(telemetryStub.calledWithMatch('ProjectContext', sinon.match(property =>
376-
property['language'] === undefined &&
377-
property['compiler'] === undefined &&
378-
property['standardVersion'] === undefined &&
379-
property['originalStandardVersion'] === 'gnu++17' &&
380-
property['targetPlatform'] === undefined)));
422+
ok(telemetryProperties["targetArchitecture"] === 'bar');
423+
ok(telemetryProperties["filters"] === undefined);
424+
ok(telemetryProperties["language"] === undefined);
425+
ok(telemetryProperties["compiler"] === undefined);
426+
ok(telemetryProperties["standardVersion"] === undefined);
427+
ok(telemetryProperties["originalStandardVersion"] === 'gnu++17');
428+
ok(telemetryProperties["targetPlatform"] === undefined);
429+
ok(telemetryMetrics["compilerArgumentCount"] === 0);
381430
ok(result, 'result should not be undefined');
382431
ok(result.language === '');
383432
ok(result.compiler === '');

0 commit comments

Comments
 (0)