Skip to content

Commit 0a6d198

Browse files
authored
Merge pull request microsoft#167385 from microsoft/hediet/conflict-marker-telemetry
Add telemetry for conflict markers
2 parents 9dba538 + 1f0fba4 commit 0a6d198

File tree

6 files changed

+490
-6
lines changed

6 files changed

+490
-6
lines changed

extensions/merge-conflict/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"supported": true
2020
}
2121
},
22+
"enabledApiProposals": [
23+
"telemetryLogger"
24+
],
2225
"activationEvents": [
2326
"onStartupFinished"
2427
],
@@ -165,7 +168,9 @@
165168
}
166169
}
167170
},
168-
"dependencies": {},
171+
"dependencies": {
172+
"@vscode/extension-telemetry": "0.7.1-preview"
173+
},
169174
"devDependencies": {
170175
"@types/node": "16.x"
171176
},

extensions/merge-conflict/src/documentMergeConflict.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55
import * as interfaces from './interfaces';
66
import * as vscode from 'vscode';
7+
import type TelemetryReporter from '@vscode/extension-telemetry';
78

89
export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict {
910

@@ -13,7 +14,7 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
1314
public commonAncestors: interfaces.IMergeRegion[];
1415
public splitter: vscode.Range;
1516

16-
constructor(descriptor: interfaces.IDocumentMergeConflictDescriptor) {
17+
constructor(descriptor: interfaces.IDocumentMergeConflictDescriptor, private readonly telemetryReporter: TelemetryReporter) {
1718
this.range = descriptor.range;
1819
this.current = descriptor.current;
1920
this.incoming = descriptor.incoming;
@@ -22,6 +23,25 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
2223
}
2324

2425
public commitEdit(type: interfaces.CommitType, editor: vscode.TextEditor, edit?: vscode.TextEditorEdit): Thenable<boolean> {
26+
function commitTypeToString(type: interfaces.CommitType): string {
27+
switch (type) {
28+
case interfaces.CommitType.Current:
29+
return 'current';
30+
case interfaces.CommitType.Incoming:
31+
return 'incoming';
32+
case interfaces.CommitType.Both:
33+
return 'both';
34+
}
35+
}
36+
37+
/* __GDPR__
38+
"mergeMarkers.accept" : {
39+
"owner": "hediet",
40+
"comment": "Used to understand how the inline merge editor experience is used.",
41+
"resolution": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Indicates how the merge conflict was resolved by the user" }
42+
}
43+
*/
44+
this.telemetryReporter.sendTelemetryEvent('mergeMarkers.accept', { resolution: commitTypeToString(type) });
2545

2646
if (edit) {
2747

extensions/merge-conflict/src/documentTracker.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
77
import { MergeConflictParser } from './mergeConflictParser';
88
import * as interfaces from './interfaces';
99
import { Delayer } from './delayer';
10+
import TelemetryReporter from '@vscode/extension-telemetry';
1011

1112
class ScanTask {
1213
public origins: Set<string> = new Set<string>();
@@ -47,6 +48,8 @@ export default class DocumentMergeConflictTracker implements vscode.Disposable,
4748
private cache: Map<string, ScanTask> = new Map();
4849
private delayExpireTime: number = 0;
4950

51+
constructor(private readonly telemetryReporter: TelemetryReporter) { }
52+
5053
getConflicts(document: vscode.TextDocument, origin: string): PromiseLike<interfaces.IDocumentMergeConflict[]> {
5154
// Attempt from cache
5255

@@ -109,14 +112,35 @@ export default class DocumentMergeConflictTracker implements vscode.Disposable,
109112
this.cache.clear();
110113
}
111114

115+
private readonly seenDocumentsWithConflicts = new Set<string>();
116+
112117
private getConflictsOrEmpty(document: vscode.TextDocument, _origins: string[]): interfaces.IDocumentMergeConflict[] {
113118
const containsConflict = MergeConflictParser.containsConflict(document);
114119

115120
if (!containsConflict) {
116121
return [];
117122
}
118123

119-
const conflicts = MergeConflictParser.scanDocument(document);
124+
const conflicts = MergeConflictParser.scanDocument(document, this.telemetryReporter);
125+
126+
const key = document.uri.toString();
127+
// Don't report telemetry for the same document twice. This is an approximation, but good enough.
128+
// Otherwise redo/undo could trigger this event multiple times.
129+
if (!this.seenDocumentsWithConflicts.has(key)) {
130+
this.seenDocumentsWithConflicts.add(key);
131+
132+
/* __GDPR__
133+
"mergeMarkers.documentWithConflictMarkersOpened" : {
134+
"owner": "hediet",
135+
"comment": "Used to determine how many documents with conflicts are opened.",
136+
"conflictCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "comment": "Total number of conflict counts" }
137+
}
138+
*/
139+
this.telemetryReporter.sendTelemetryEvent('mergeMarkers.documentWithConflictMarkersOpened', {}, {
140+
conflictCount: conflicts.length,
141+
});
142+
}
143+
120144
return conflicts;
121145
}
122146

extensions/merge-conflict/src/mergeConflictParser.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import * as vscode from 'vscode';
66
import * as interfaces from './interfaces';
77
import { DocumentMergeConflict } from './documentMergeConflict';
8+
import TelemetryReporter from '@vscode/extension-telemetry';
89

910
const startHeaderMarker = '<<<<<<<';
1011
const commonAncestorsMarker = '|||||||';
@@ -20,7 +21,7 @@ interface IScanMergedConflict {
2021

2122
export class MergeConflictParser {
2223

23-
static scanDocument(document: vscode.TextDocument): interfaces.IDocumentMergeConflict[] {
24+
static scanDocument(document: vscode.TextDocument, telemetryReporter: TelemetryReporter): interfaces.IDocumentMergeConflict[] {
2425

2526
// Scan each line in the document, we already know there is at least a <<<<<<< and
2627
// >>>>>> marker within the document, we need to group these into conflict ranges.
@@ -81,7 +82,7 @@ export class MergeConflictParser {
8182

8283
return conflictDescriptors
8384
.filter(Boolean)
84-
.map(descriptor => new DocumentMergeConflict(descriptor));
85+
.map(descriptor => new DocumentMergeConflict(descriptor, telemetryReporter));
8586
}
8687

8788
private static scanItemTolMergeConflictDescriptor(document: vscode.TextDocument, scanned: IScanMergedConflict): interfaces.IDocumentMergeConflictDescriptor | null {

extensions/merge-conflict/src/services.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@ import CommandHandler from './commandHandler';
99
import ContentProvider from './contentProvider';
1010
import Decorator from './mergeDecorator';
1111
import * as interfaces from './interfaces';
12+
import TelemetryReporter from '@vscode/extension-telemetry';
1213

1314
const ConfigurationSectionName = 'merge-conflict';
1415

1516
export default class ServiceWrapper implements vscode.Disposable {
1617

1718
private services: vscode.Disposable[] = [];
19+
private telemetryReporter: TelemetryReporter;
1820

1921
constructor(private context: vscode.ExtensionContext) {
22+
const { aiKey } = context.extension.packageJSON as { aiKey: string };
23+
this.telemetryReporter = new TelemetryReporter(aiKey);
24+
context.subscriptions.push(this.telemetryReporter);
2025
}
2126

2227
begin() {
2328

2429
const configuration = this.createExtensionConfiguration();
25-
const documentTracker = new DocumentTracker();
30+
const documentTracker = new DocumentTracker(this.telemetryReporter);
2631

2732
this.services.push(
2833
documentTracker,

0 commit comments

Comments
 (0)