Skip to content

Commit 3d239bd

Browse files
VSCODE-114: Track playground loaded and saved events (#90)
* feat: track playground loaded and saved events * test: replace some done tests with async * test: catch errors that appear in the tests results * refactor: trigger azure * refactor: trigger azure * refactor: trigger azure
1 parent 2d15f6c commit 3d239bd

17 files changed

+1550
-1640
lines changed

src/connectionController.ts

Lines changed: 22 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,11 @@ import { EventEmitter } from 'events';
1111
import { StorageController, StorageVariables } from './storage';
1212
import { SavedConnection, StorageScope } from './storage/storageController';
1313
import { getNodeModule } from './utils/getNodeModule';
14-
import TelemetryController, {
15-
TelemetryEventTypes
16-
} from './telemetry/telemetryController';
17-
import { getCloudInfo } from 'mongodb-cloud-info';
14+
import TelemetryController from './telemetry/telemetryController';
1815

1916
const { name, version } = require('../package.json');
2017
const log = createLogger('connection controller');
2118
const MAX_CONNECTION_NAME_LENGTH = 512;
22-
const ATLAS_REGEX = /mongodb.net[:/]/i;
23-
const LOCALHOST_REGEX = /(localhost|127\.0\.0\.1)/i;
2419

2520
type KeyTar = typeof keytarType;
2621

@@ -245,6 +240,17 @@ export default class ConnectionController {
245240
});
246241
};
247242

243+
public sendTelemetry(
244+
newDataService: DataServiceType,
245+
connectionType: ConnectionTypes
246+
) {
247+
// Send metrics to Segment
248+
this._telemetryController.trackNewConnection(
249+
newDataService,
250+
connectionType
251+
);
252+
}
253+
248254
public parseNewConnectionAndConnect = (
249255
newConnectionModel: ConnectionModelType
250256
): Promise<boolean> => {
@@ -309,82 +315,13 @@ export default class ConnectionController {
309315
return resolve(false);
310316
}
311317

312-
resolve(true);
318+
return resolve(true);
313319
},
314320
reject
315321
);
316322
});
317323
};
318324

319-
public async getCloudInfoFromDataService(firstServerHostname: string) {
320-
const cloudInfo = await getCloudInfo(firstServerHostname);
321-
let isPublicCloud = false;
322-
let publicCloudName: string | null = null;
323-
324-
if (cloudInfo.isAws) {
325-
isPublicCloud = true;
326-
publicCloudName = 'aws';
327-
} else if (cloudInfo.isGcp) {
328-
isPublicCloud = true;
329-
publicCloudName = 'gcp';
330-
} else if (cloudInfo.isAzure) {
331-
isPublicCloud = true;
332-
publicCloudName = 'azure';
333-
}
334-
335-
return { isPublicCloud, publicCloudName };
336-
}
337-
338-
private async sendTelemetry(
339-
dataService: DataServiceType,
340-
connectionType: ConnectionTypes
341-
): Promise<void> {
342-
dataService.instance({}, async (error: any, data: any) => {
343-
if (error) {
344-
log.error('TELEMETRY data service error', error);
345-
}
346-
347-
if (data) {
348-
try {
349-
const firstServerHostname = dataService.client.model.hosts[0].host;
350-
const cloudInfo = await this.getCloudInfoFromDataService(
351-
firstServerHostname
352-
);
353-
const nonGenuineServerName = data.genuineMongoDB.isGenuine
354-
? null
355-
: data.genuineMongoDB.dbType;
356-
const telemetryData = {
357-
is_atlas: !!data.client.s.url.match(ATLAS_REGEX),
358-
is_localhost: !!data.client.s.url.match(LOCALHOST_REGEX),
359-
is_data_lake: data.dataLake.isDataLake,
360-
is_enterprise: data.build.enterprise_module,
361-
is_public_cloud: cloudInfo.isPublicCloud,
362-
public_cloud_name: cloudInfo.publicCloudName,
363-
is_genuine: data.genuineMongoDB.isGenuine,
364-
non_genuine_server_name: nonGenuineServerName,
365-
server_version: data.build.version,
366-
server_arch: data.build.raw.buildEnvironment.target_arch,
367-
server_os: data.build.raw.buildEnvironment.target_os,
368-
is_used_connect_screen:
369-
connectionType === ConnectionTypes.CONNECTION_FORM,
370-
is_used_command_palette:
371-
connectionType === ConnectionTypes.CONNECTION_STRING,
372-
is_used_saved_connection:
373-
connectionType === ConnectionTypes.CONNECTION_ID
374-
};
375-
376-
// Send metrics to Segment
377-
this._telemetryController.track(
378-
TelemetryEventTypes.NEW_CONNECTION,
379-
telemetryData
380-
);
381-
} catch (error) {
382-
log.error('TELEMETRY cloud info error', error);
383-
}
384-
}
385-
});
386-
}
387-
388325
public connect = async (
389326
connectionId: string,
390327
connectionModel: ConnectionModelType,
@@ -449,9 +386,8 @@ export default class ConnectionController {
449386
this.eventEmitter.emit(DataServiceEventTypes.CONNECTIONS_DID_CHANGE);
450387
this.eventEmitter.emit(DataServiceEventTypes.ACTIVE_CONNECTION_CHANGED);
451388

452-
if (this._telemetryController.needTelemetry()) {
453-
this.sendTelemetry(newDataService, connectionType);
454-
}
389+
// Send metrics to Segment
390+
this.sendTelemetry(newDataService, connectionType);
455391

456392
return resolve(true);
457393
});
@@ -659,13 +595,13 @@ export default class ConnectionController {
659595
const connectionNameToRemove:
660596
| string
661597
| undefined = await vscode.window.showQuickPick(
662-
connectionIds.map(
663-
(id, index) => `${index + 1}: ${this._connections[id].name}`
664-
),
665-
{
666-
placeHolder: 'Choose a connection to remove...'
667-
}
668-
);
598+
connectionIds.map(
599+
(id, index) => `${index + 1}: ${this._connections[id].name}`
600+
),
601+
{
602+
placeHolder: 'Choose a connection to remove...'
603+
}
604+
);
669605

670606
if (!connectionNameToRemove) {
671607
return Promise.resolve(false);

src/editors/playgroundController.ts

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import * as vscode from 'vscode';
2-
32
import ConnectionController, {
43
DataServiceEventTypes
54
} from '../connectionController';
65
import { LanguageServerController } from '../language';
7-
import TelemetryController, {
8-
TelemetryEventTypes,
9-
TelemetryEventProperties
10-
} from '../telemetry/telemetryController';
6+
import TelemetryController from '../telemetry/telemetryController';
117
import ActiveConnectionCodeLensProvider from './activeConnectionCodeLensProvider';
128
import { OutputChannel, ProgressLocation, TextEditor } from 'vscode';
139
import playgroundTemplate from '../templates/playgroundTemplate';
@@ -137,43 +133,15 @@ export default class PlaygroundController {
137133
});
138134
}
139135

140-
public prepareTelemetry(res: any): TelemetryEventProperties {
141-
let type = 'other';
142-
143-
if (!res.shellApiType) {
144-
return { type };
145-
}
146-
147-
const shellApiType = res.shellApiType.toLocaleLowerCase();
148-
149-
// See: https://github.com/mongodb-js/mongosh/blob/master/packages/shell-api/src/shell-api.js
150-
if (shellApiType.includes('insert')) {
151-
type = 'insert';
152-
} else if (shellApiType.includes('update')) {
153-
type = 'update';
154-
} else if (shellApiType.includes('delete')) {
155-
type = 'delete';
156-
} else if (shellApiType.includes('aggregation')) {
157-
type = 'aggregation';
158-
} else if (shellApiType.includes('cursor')) {
159-
type = 'query';
160-
}
161-
162-
return { type };
163-
}
164-
165136
public async evaluate(codeToEvaluate: string): Promise<any> {
166-
// Send a request to the language server to execute scripts from a playground
137+
// Send a request to the language server to execute scripts from a playground.
167138
const result = await this._languageServerController.executeAll(
168139
codeToEvaluate
169140
);
170141

171-
if (result && this._telemetryController.needTelemetry()) {
172-
// Send metrics to Segment
173-
this._telemetryController.track(
174-
TelemetryEventTypes.PLAYGROUND_CODE_EXECUTED,
175-
this.prepareTelemetry(result)
176-
);
142+
// Send metrics to Segment.
143+
if (result) {
144+
this._telemetryController.trackPlaygroundCodeExecuted(result);
177145
}
178146

179147
return Promise.resolve(result);
@@ -196,7 +164,7 @@ export default class PlaygroundController {
196164
},
197165
async (progress, token) => {
198166
token.onCancellationRequested(async () => {
199-
// If a user clicked the cancel button terminate all playground scripts
167+
// If a user clicked the cancel button terminate all playground scripts.
200168
this._languageServerController.cancelAll();
201169
this._outputChannel.clear();
202170
this._outputChannel.show(true);
@@ -206,7 +174,7 @@ export default class PlaygroundController {
206174

207175
const codeToEvaluate =
208176
this._activeTextEditor?.document.getText() || '';
209-
// Run all playground scripts
177+
// Run all playground scripts.
210178
const result = await this.evaluate(codeToEvaluate);
211179

212180
return resolve(result);

src/explorer/explorerController.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export default class ExplorerController {
3232
this._treeView = vscode.window.createTreeView('mongoDB', {
3333
treeDataProvider: this._treeController
3434
});
35-
3635
this._treeController.activateTreeViewEventHandlers(this._treeView);
3736
}
3837
};
@@ -61,13 +60,15 @@ export default class ExplorerController {
6160
if (this._treeController) {
6261
return this._treeController.refresh();
6362
}
63+
6464
return Promise.reject(new Error('No tree to refresh.'));
6565
}
6666

6767
// Exposed for testing.
6868
public getTreeView(): vscode.TreeView<vscode.TreeItem> | undefined {
6969
return this._treeView;
7070
}
71+
7172
public getTreeController(): ExplorerTreeController {
7273
return this._treeController;
7374
}

src/mdbExtensionController.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import ConnectionController from './connectionController';
99
import { EditorsController, PlaygroundController } from './editors';
1010
import { ExplorerController, CollectionTreeItem } from './explorer';
1111
import { LanguageServerController } from './language';
12-
import TelemetryController, {
13-
TelemetryEventTypes
14-
} from './telemetry/telemetryController';
12+
import TelemetryController from './telemetry/telemetryController';
1513
import { StatusView } from './views';
1614
import { createLogger } from './logging';
1715
import { StorageController } from './storage';
@@ -42,7 +40,6 @@ export default class MDBExtensionController implements vscode.Disposable {
4240
connectionController?: ConnectionController
4341
) {
4442
this._context = context;
45-
4643
this._statusView = new StatusView(context);
4744
this._storageController = new StorageController(context);
4845
this._telemetryController = new TelemetryController(
@@ -136,13 +133,8 @@ export default class MDBExtensionController implements vscode.Disposable {
136133
commandHandler: (...args: any[]) => Promise<boolean>
137134
): void => {
138135
const commandHandlerWithTelemetry = (args: any[]) => {
139-
// Send metrics to Segment
140-
this._telemetryController.track(
141-
TelemetryEventTypes.EXTENSION_COMMAND_RUN,
142-
{
143-
command
144-
}
145-
);
136+
// Send metrics to Segment.
137+
this._telemetryController.trackCommandRun(command);
146138

147139
return commandHandler(args);
148140
};
@@ -204,6 +196,7 @@ export default class MDBExtensionController implements vscode.Disposable {
204196
return new Promise((resolve, reject) => {
205197
vscode.env.clipboard.writeText(connectionString).then(() => {
206198
vscode.window.showInformationMessage('Copied to clipboard.');
199+
207200
return resolve(true);
208201
}, reject);
209202
});

0 commit comments

Comments
 (0)