Skip to content

Commit 909162b

Browse files
authored
feat(tracking): connection tracking COMPASS-5192 (#2563)
1 parent 5bbcb81 commit 909162b

File tree

3 files changed

+101
-19
lines changed

3 files changed

+101
-19
lines changed

packages/compass-connect/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@
105105
"mocha": "^7.0.1",
106106
"mocha-webpack": "^2.0.0-beta.0",
107107
"moment": "^2.27.0",
108+
"mongodb-build-info": "^1.2.0",
109+
"mongodb-cloud-info": "^1.1.3",
108110
"mongodb-connection-model": "^21.8.0",
109111
"mongodb-data-service": "^21.12.0",
110112
"mongodb-runner": "^4.8.3",

packages/compass-connect/src/stores/index.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const StateMixin = require('reflux-state-mixin');
77
const { promisify } = require('util');
88
const { getConnectionTitle, convertConnectionModelToInfo } = require('mongodb-data-service');
99
const debug = require('debug')('compass-connect:store');
10+
const { isAtlas, isLocalhost, isDigitalOcean } = require('mongodb-build-info');
11+
const { getCloudInfo } = require('mongodb-cloud-info');
1012

1113
const Actions = require('../actions');
1214
const {
@@ -19,7 +21,7 @@ const ConnectionCollection = Connection.ConnectionCollection;
1921
const userAgent = navigator.userAgent.toLowerCase();
2022

2123
const { createLoggerAndTelemetry } = require('@mongodb-js/compass-logging');
22-
const { log, mongoLogId } = createLoggerAndTelemetry('COMPASS-CONNECT-UI');
24+
const { log, track, mongoLogId } = createLoggerAndTelemetry('COMPASS-CONNECT-UI');
2325

2426
/**
2527
* A default driverUrl.
@@ -311,6 +313,14 @@ const Store = Reflux.createStore({
311313
return;
312314
}
313315

316+
const { connectionModel } = this.state;
317+
const trackEvent = {
318+
is_favorite: connectionModel.isFavorite,
319+
is_recent: Boolean(connectionModel.lastUsed && !connectionModel.isFavorite),
320+
is_new: !connectionModel.lastUsed,
321+
};
322+
track('Connection Attempt', trackEvent);
323+
314324
this.setState({
315325
currentConnectionAttempt: createConnectionAttempt(),
316326
connectingStatusText: LOADING_CONNECTION_TEXT
@@ -682,6 +692,7 @@ const Store = Reflux.createStore({
682692

683693
/**
684694
* Resets the connection after clicking on the new connection section.
695+
*
685696
*/
686697
onResetConnectionClicked() {
687698
this.state.viewType = CONNECTION_STRING_VIEW;
@@ -960,6 +971,40 @@ const Store = Reflux.createStore({
960971
}
961972
},
962973

974+
async _trackConnectionInfo() {
975+
const { dataService } = this;
976+
const {
977+
dataLake,
978+
genuineMongoDB,
979+
host,
980+
build,
981+
} = await dataService.instance();
982+
const {
983+
hostname,
984+
authMechanism,
985+
} = this.state.connectionModel;
986+
const { isAws, isAzure, isGcp } = await getCloudInfo(hostname);
987+
const isPublicCloud = isAws || isAzure || isGcp;
988+
const publicCloudName = isAws ? 'AWS' : isAzure ? 'Azure' : isGcp ? 'GCP' : '';
989+
990+
const trackEvent = {
991+
is_localhost: isLocalhost(hostname),
992+
is_atlas: isAtlas(hostname),
993+
is_dataLake: dataLake.isDataLake,
994+
is_enterprise: build.isEnterprise,
995+
is_public_cloud: isPublicCloud,
996+
is_do: isDigitalOcean(hostname),
997+
public_cloud_name: publicCloudName,
998+
is_genuine: genuineMongoDB.isGenuine,
999+
non_genuine_server_name: genuineMongoDB.dbType,
1000+
server_version: host.kernel_version,
1001+
server_arch: host.arch,
1002+
server_os_family: host.os_family,
1003+
auth_type: authMechanism ?? '',
1004+
};
1005+
track('New Connection', trackEvent);
1006+
},
1007+
9631008
_onConnectSuccess(dataService, connectionInfo) {
9641009
const connectionModel = this.state.connectionModel;
9651010
const currentSaved = this.state.connections[connectionModel._id];
@@ -996,6 +1041,8 @@ const Store = Reflux.createStore({
9961041
// bar, which is hidden after the instance information is loaded
9971042
// in another plugin.
9981043
this.StatusActions.showIndeterminateProgressBar();
1044+
1045+
void this._trackConnectionInfo();
9991046
},
10001047

10011048
/**

packages/compass-e2e-tests/tests/logging.test.js

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ describe('Logging and Telemetry integration', function () {
4747
);
4848
});
4949

50-
it('contains an identify call', function () {
50+
it('tracks an event for identify call', function () {
5151
const identify = telemetry
5252
.events()
5353
.find((entry) => entry.type === 'identify');
5454
expect(identify.traits.platform).to.equal(process.platform);
5555
expect(identify.traits.arch).to.equal(process.arch);
5656
});
5757

58-
it('contains a call for the welcome tour being closed', function () {
58+
it('tracks an event for the welcome tour being closed', function () {
5959
const tourClosed = telemetry
6060
.events()
6161
.find((entry) => entry.event === 'Tour Closed');
@@ -66,21 +66,54 @@ describe('Logging and Telemetry integration', function () {
6666
expect(tourClosed.properties.compass_channel).to.be.a('string');
6767
});
6868

69-
it('contains call for shell use events', function () {
69+
it('tracks an event for shell use', function () {
7070
const shellUse = telemetry
7171
.events()
7272
.find((entry) => entry.event === 'Shell Use');
7373
expect(shellUse.properties.compass_version).to.be.a('string');
7474
});
7575

76-
it('contains call for shell connection events', function () {
76+
it('tracks an event for shell connection', function () {
7777
const shellNewConnection = telemetry
7878
.events()
7979
.find((entry) => entry.event === 'Shell New Connection');
8080
expect(shellNewConnection.properties.is_localhost).to.equal(true);
8181
});
8282

83-
it('contains calls for screens that were accessed', function () {
83+
it('tracks an event for an attempt to establish a new connection', function () {
84+
const connectionAttempt = telemetry
85+
.events()
86+
.find((entry) => entry.event === 'Connection Attempt');
87+
expect(connectionAttempt.properties.is_favorite).to.equal(false);
88+
expect(connectionAttempt.properties.is_recent).to.equal(false);
89+
expect(connectionAttempt.properties.is_new).to.equal(true);
90+
});
91+
92+
it('tracks an event when a connection is established', function () {
93+
const connectionAttempt = telemetry
94+
.events()
95+
.find((entry) => entry.event === 'New Connection');
96+
expect(connectionAttempt.properties.is_localhost).to.equal(true);
97+
expect(connectionAttempt.properties.is_atlas).to.equal(false);
98+
expect(connectionAttempt.properties.is_dataLake).to.equal(false);
99+
expect(connectionAttempt.properties.is_enterprise).to.equal(false);
100+
expect(connectionAttempt.properties.is_public_cloud).to.equal(false);
101+
expect(connectionAttempt.properties.is_do).to.equal(false);
102+
103+
expect(connectionAttempt.properties.public_cloud_name).to.be.a(
104+
'string'
105+
);
106+
expect(connectionAttempt.properties.is_genuine).to.be.a('boolean');
107+
expect(connectionAttempt.properties.non_genuine_server_name).to.be.a(
108+
'string'
109+
);
110+
expect(connectionAttempt.properties.server_version).to.be.a('string');
111+
expect(connectionAttempt.properties.server_arch).to.be.a('string');
112+
expect(connectionAttempt.properties.server_os_family).to.be.a('string');
113+
expect(connectionAttempt.properties.auth_type).to.be.a('string');
114+
});
115+
116+
it('tracks an event for screens that were accessed', function () {
84117
expect(telemetry.screens()).to.include('databases');
85118
});
86119
});
@@ -295,12 +328,10 @@ describe('Logging and Telemetry integration', function () {
295328
];
296329

297330
let criticalPathActualLogs;
331+
const testedIndexes = new Set();
298332

299333
// eslint-disable-next-line mocha/no-hooks-for-single-case
300334
before(function () {
301-
const criticalPathIds = new Set(
302-
criticalPathExpectedLogs.map((entry) => entry.id)
303-
);
304335
criticalPathActualLogs = compassLog.filter((entry) => {
305336
// Remove most mongosh entries as they are quite noisy
306337
if (
@@ -312,29 +343,31 @@ describe('Logging and Telemetry integration', function () {
312343
return false;
313344
}
314345

315-
return criticalPathIds.has(entry.id);
346+
return true;
316347
});
317348
});
318349

319350
// eslint-disable-next-line mocha/no-setup-in-describe
320-
criticalPathExpectedLogs.forEach((expected, i) => {
351+
criticalPathExpectedLogs.forEach((expected) => {
321352
it(`logs "${expected.msg}"`, function () {
322-
if (!criticalPathActualLogs[i]) {
353+
const actualLogIndex = criticalPathActualLogs.findIndex(
354+
({ id }, index) => id === expected.id && !testedIndexes.has(index)
355+
);
356+
if (actualLogIndex < 0) {
323357
throw new Error(
324-
`No criticalPathActualLog for index ${i} expected ${JSON.stringify(
325-
expected
326-
)} was empty`
358+
`No actual log found for expected ${JSON.stringify(expected)}`
327359
);
328360
}
329361

362+
testedIndexes.add(actualLogIndex);
330363
const { attr: expectedAttr, ...expectedWithoutAttr } = expected;
331-
const { attr: actualAttr, ...actualWihoutAttr } =
332-
criticalPathActualLogs[i];
364+
const { attr: actualAttr, ...actualWithoutAttr } =
365+
criticalPathActualLogs[actualLogIndex];
333366

334367
// Timestamps vary between each execution
335-
delete actualWihoutAttr.t;
368+
delete actualWithoutAttr.t;
336369

337-
expect(expectedWithoutAttr).to.deep.equal(actualWihoutAttr);
370+
expect(expectedWithoutAttr).to.deep.equal(actualWithoutAttr);
338371

339372
// we already know this would fail the expectation
340373
if (

0 commit comments

Comments
 (0)