update analytics (#99)

* replace mixpanel with amplitude

* remove unused uuid require

* include partial count fields to allow easier analysis

* enable real logging

* record extension deactivation
This commit is contained in:
Dave Holoway
2020-07-21 20:47:37 +01:00
committed by GitHub
parent d15a7bd911
commit 05b3877bcb
8 changed files with 95 additions and 119 deletions

View File

@@ -12,8 +12,11 @@ const { selectTargetDevice } = require('./src/utils/device');
/** /**
* @param {vscode.ExtensionContext} context * @param {vscode.ExtensionContext} context
* @param {string} uid
* @param {number} session_id
* @param {*} vscode_props
*/ */
async function createLanguageClient(context) { async function createLanguageClient(context, uid, session_id, vscode_props) {
// The server is implemented in node // The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('langserver', 'server.js')); let serverModule = context.asAbsolutePath(path.join('langserver', 'server.js'));
// The debug options for the server // The debug options for the server
@@ -45,8 +48,6 @@ async function createLanguageClient(context) {
} }
const sourceFiles = (await vscode.workspace.findFiles(`${globSearchRoot}**/*.java`, null, 1000, null)).map(uri => uri.toString()); const sourceFiles = (await vscode.workspace.findFiles(`${globSearchRoot}**/*.java`, null, 1000, null)).map(uri => uri.toString());
const mpids = analytics.getIDs(context);
// Options to control the language client // Options to control the language client
/** @type {import('vscode-languageclient').LanguageClientOptions} */ /** @type {import('vscode-languageclient').LanguageClientOptions} */
let clientOptions = { let clientOptions = {
@@ -57,11 +58,11 @@ async function createLanguageClient(context) {
initializationOptions: { initializationOptions: {
// extensionPath points to the root of the extension (the folder where this file is) // extensionPath points to the root of the extension (the folder where this file is)
extensionPath: context.extensionPath, extensionPath: context.extensionPath,
mpuid: mpids.uid, uid,
mpsid: mpids.sid, session_id,
vscode_props,
initialSettings: config, initialSettings: config,
sourceFiles, sourceFiles,
vscodeVersion: vscode.version,
workspaceFolders: (vscode.workspace.workspaceFolders || []).map(z => z.uri.toString()), workspaceFolders: (vscode.workspace.workspaceFolders || []).map(z => z.uri.toString()),
}, },
synchronize: { synchronize: {
@@ -114,10 +115,18 @@ function activate(context) {
/* Only the logcat stuff is configured here. The debugger is launched from src/debugMain.js */ /* Only the logcat stuff is configured here. The debugger is launched from src/debugMain.js */
AndroidContentProvider.register(context, vscode.workspace); AndroidContentProvider.register(context, vscode.workspace);
const mpids = analytics.getIDs(context); const { uid } = analytics.getIDs(context);
analytics.init(undefined, mpids.uid, mpids.sid, package_json, { vscode_version: vscode.version }); const session_id = Math.trunc(Math.random() * Number.MAX_SAFE_INTEGER);
const vscode_props = {
appName: vscode.env.appName,
language: vscode.env.language,
shell: vscode.env.shell,
uiKind: vscode.env.uiKind,
vscode_version: vscode.version,
}
analytics.init(undefined, uid, session_id, '', package_json, vscode_props, 'extension-start');
createLanguageClient(context).then(client => { createLanguageClient(context, uid, session_id, vscode_props).then(client => {
languageClient = client; languageClient = client;
refreshLanguageServerEnabledState(); refreshLanguageServerEnabledState();
}); });
@@ -172,6 +181,7 @@ function activate(context) {
// this method is called when your extension is deactivated // this method is called when your extension is deactivated
function deactivate() { function deactivate() {
analytics.event('extension-deactivate');
} }
exports.activate = activate; exports.activate = activate;

View File

@@ -1,43 +1,53 @@
const os = require('os'); const os = require('os');
let mp; const uuid = require('uuid').v4;
let client;
/** @type {string} */ /** @type {string} */
let uid; let uid;
/** @type {string} */ /** @type {string} */
let sid; let did = uuid();
/** @type {number} */
let session_id;
/** @type {Map<string,[number,number]>} */ /** @type {Map<string,[number,number]>} */
const timeLabels = new Map(); const timeLabels = new Map();
let session_start = Date.now(); let session_start = Date.now();
/** @type {string|Promise<string>} */ /** @type {string|Promise<string>} */
let ip = getCurrentIP() let ip = '';
.catch(() => null)
.then(res => ip = res);
let queued_events = null; let queued_events = null;
let package_info = null;
let vscode_info = null;
/** /**
* @param {string} [t] * @param {string} [t]
* @param {string} [u] * @param {string} u
* @param {string} [s] * @param {number} s
* @param {{name:string,version:string}} [package_json] * @param {string} ipaddr
* @param {*} [props] * @param {{name:string,version:string}} package_json
* @param {*} vscode_props
* @param {string} caller
*/ */
function init(t = '0cca95950055c6553804a46ce7e3df18', u, s, package_json, props) { function init(t = '94635b4642d80407accd3739fa35bed6', u, s, ipaddr, package_json, vscode_props, caller) {
if (mp) { if (client) {
return; return;
} }
try { try {
mp = require('mixpanel').init(t); client = require('@amplitude/node').init(t);
} }
catch { catch {
return; return;
} }
uid = u; uid = u;
sid = s; session_id = s || Math.trunc(Math.random() * Number.MAX_SAFE_INTEGER);
ip = ipaddr || (getCurrentIP()
.catch(() => '')
.then(res => ip = res));
package_info = package_json;
vscode_info = vscode_props;
if (!props) { if (!caller) {
return; return;
} }
const now = new Date(); const now = new Date();
event(`${package_json.name}-start`, { event(caller, {
extension: package_json.name, extension: package_json.name,
ext_version: package_json.version, ext_version: package_json.version,
arch: process.arch, arch: process.arch,
@@ -48,7 +58,7 @@ function init(t = '0cca95950055c6553804a46ce7e3df18', u, s, package_json, props)
release: os.release(), release: os.release(),
localtime: now.toTimeString(), localtime: now.toTimeString(),
tz: now.getTimezoneOffset(), tz: now.getTimezoneOffset(),
...props ...vscode_props,
}); });
} }
@@ -69,7 +79,7 @@ function getCurrentIP() {
* @param {*} [properties] * @param {*} [properties]
*/ */
function event(eventName, properties) { function event(eventName, properties) {
if (!mp) { if (!client || !eventName || (!uid && !did) || !ip) {
return; return;
} }
if (queued_events) { if (queued_events) {
@@ -86,23 +96,21 @@ function event(eventName, properties) {
return; return;
} }
try { try {
if (uid) { client.logEvent({
mp.track(eventName, { event_type: eventName,
user_id: uid,
device_id: uid ? undefined : did,
app_version: package_info.version,
ip, ip,
distinct_id: uid, language: vscode_info.language,
session_id: sid, os_name: process.platform,
os_version: os.release(),
session_id,
event_properties: {
session_length: Math.trunc((Date.now() - session_start) / 60e3), session_length: Math.trunc((Date.now() - session_start) / 60e3),
...properties, ...properties,
});
} else {
mp.track(eventName, {
ip,
platform: process.platform,
release: os.release(),
node_version: process.version,
...properties,
});
} }
});
} catch {} } catch {}
} }
@@ -149,29 +157,18 @@ function timeEnd(label, time_unit = 'ms', additionalProps = {}) {
function getIDs(context) { function getIDs(context) {
if (!context || !context.globalState) { if (!context || !context.globalState) {
return { return {
uid: '', sid: '' uid: '',
}; };
} }
let uuidv4 = () => {
try {
uuidv4 = require('uuid').v4;
return uuidv4();
} catch {
return '';
}
}
let u = uid || (uid = context.globalState.get('mix-panel-id')); let u = uid || (uid = context.globalState.get('mix-panel-id'));
if (typeof u !== 'string' || u.length > 36) { if (typeof u !== 'string' || u.length > 36) {
u = uid = uuidv4(); u = uid = uuid();
context.globalState.update('mix-panel-id', u); context.globalState.update('mix-panel-id', u);
} }
let s = sid || (sid = uuidv4());
return { return {
uid: u, uid: u,
sid: s,
} }
} }
exports.init = init; exports.init = init;
exports.event = event; exports.event = event;
exports.time = time; exports.time = time;

View File

@@ -370,7 +370,10 @@ async function getCompletionItems(params, liveParsers, androidLibrary) {
completionRequestCount += 1; completionRequestCount += 1;
if ((completionRequestCount === 1) || (completionRequestCount === 5) || ((completionRequestCount % 25) === 0)) { if ((completionRequestCount === 1) || (completionRequestCount === 5) || ((completionRequestCount % 25) === 0)) {
event('completion-requests', { comp_req_count: completionRequestCount }); event('completion-requests', {
comp_req_count: completionRequestCount, // total count for this session
comp_req_partial_count: (completionRequestCount % 25) || 25,
});
} }
let parsed = docinfo.parsed; let parsed = docinfo.parsed;

View File

@@ -41,7 +41,10 @@ async function getSignatureHelp(request, liveParsers) {
methodsigRequestCount += 1; methodsigRequestCount += 1;
if ((methodsigRequestCount === 1) || (methodsigRequestCount === 5) || ((methodsigRequestCount % 25) === 0)) { if ((methodsigRequestCount === 1) || (methodsigRequestCount === 5) || ((methodsigRequestCount % 25) === 0)) {
event('method-sig-requests', { methsig_req_count: methodsigRequestCount }); event('method-sig-requests', {
methsig_req_count: methodsigRequestCount,
methsig_req_partial_count: (methodsigRequestCount % 25) || 25,
});
} }
// locate the token at the requested position // locate the token at the requested position

View File

@@ -4,20 +4,26 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@amplitude/node": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@amplitude/node/-/node-0.3.3.tgz",
"integrity": "sha512-Uzg4MRAuD053Ex67Iu2lm2GovnVte1uKI3q7CXlMCYZ9ylZmAkPbTnjg9OVyD4f+IiUfgK4p3bE7r9p7jqSDLA==",
"requires": {
"@amplitude/types": "^0.3.2",
"tslib": "^1.9.3"
}
},
"@amplitude/types": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-0.3.2.tgz",
"integrity": "sha512-7+m7nhJMFGbpsppOUsCH8f4FOFyAxgKFuXkKknU/LP2CMYVjWEIoLTKKgaJPc2c8wXaK5KPXVetb8VeiGbuaGg=="
},
"@types/node": { "@types/node": {
"version": "13.13.4", "version": "13.13.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz",
"integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==", "integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==",
"dev": true "dev": true
}, },
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -79,14 +85,6 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
},
"duplexer2": { "duplexer2": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
@@ -95,19 +93,6 @@
"readable-stream": "^2.0.2" "readable-stream": "^2.0.2"
} }
}, },
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"requires": {
"es6-promise": "^4.0.3"
}
},
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -142,15 +127,6 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
}, },
"https-proxy-agent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz",
"integrity": "sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ==",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
}
},
"inflight": { "inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -195,14 +171,6 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}, },
"mixpanel": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/mixpanel/-/mixpanel-0.11.0.tgz",
"integrity": "sha512-TS7AkCmfC+vGshlCOjEcITFoFxlt5fdSEqmN+d+pTXAhE5v+jPQW2uUcn9W+Oq4NVXz+kdskU09dsm9vmNl0ig==",
"requires": {
"https-proxy-agent": "3.0.0"
}
},
"mkdirp": { "mkdirp": {
"version": "0.5.5", "version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
@@ -211,11 +179,6 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -279,6 +242,11 @@
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
"integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
}, },
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
},
"unzipper": { "unzipper": {
"version": "0.10.11", "version": "0.10.11",
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",

View File

@@ -9,8 +9,8 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@amplitude/node": "^0.3.3",
"java-mti": "adelphes/java-mti#ec164ac", "java-mti": "adelphes/java-mti#ec164ac",
"mixpanel": "0.11.0",
"uuid": "8.2.0", "uuid": "8.2.0",
"vscode-languageserver": "6.1.1", "vscode-languageserver": "6.1.1",
"vscode-languageserver-textdocument": "1.0.1", "vscode-languageserver-textdocument": "1.0.1",

View File

@@ -135,7 +135,7 @@ connection.onInitialize((params) => {
} }
Settings.set(startupOpts.initialSettings); Settings.set(startupOpts.initialSettings);
analytics.init(undefined, startupOpts.mpuid, uuidv4(), package_json, { vscode_version: startupOpts.vscodeVersion }); analytics.init(undefined, startupOpts.uid, startupOpts.session_id, '', package_json, startupOpts.vscode_props, 'langserver-start');
loadCodeCompletionLibrary(startupOpts.extensionPath, Settings.codeCompletionLibraries); loadCodeCompletionLibrary(startupOpts.extensionPath, Settings.codeCompletionLibraries);

View File

@@ -6,7 +6,6 @@ const {
// node and external modules // node and external modules
const os = require('os'); const os = require('os');
const path = require('path'); const path = require('path');
const uuidv4 = require('uuid').v4;
// our stuff // our stuff
const { ADBClient } = require('./adbclient'); const { ADBClient } = require('./adbclient');
@@ -111,9 +110,8 @@ class AndroidDebugSession extends DebugSession {
this.terminate_reason = ''; this.terminate_reason = '';
this.session_id = uuidv4();
this.session_start = new Date(); this.session_start = new Date();
analytics.init(); analytics.init(undefined, undefined, undefined, '', require('../package.json'), {}, 'debugger-start');
// this debugger uses one-based lines and columns // this debugger uses one-based lines and columns
this.setDebuggerLinesStartAt1(true); this.setDebuggerLinesStartAt1(true);
@@ -445,8 +443,7 @@ class AndroidDebugSession extends DebugSession {
await this.dbgr.resume(); await this.dbgr.resume();
analytics.event('debug-started', { analytics.event('debug-started', {
dbg_session_id: this.session_id, dbg_start: this.session_start.toTimeString(),
dbg_start: this.session_start.toLocaleTimeString(),
dbg_tz: this.session_start.getTimezoneOffset(), dbg_tz: this.session_start.getTimezoneOffset(),
dbg_kind: 'attach', dbg_kind: 'attach',
dbg_device_api: this.device_api_level, dbg_device_api: this.device_api_level,
@@ -611,8 +608,7 @@ class AndroidDebugSession extends DebugSession {
await this.dbgr.resume(); await this.dbgr.resume();
analytics.event('debug-started', { analytics.event('debug-started', {
dbg_session_id: this.session_id, dbg_start: this.session_start.toTimeString(),
dbg_start: this.session_start.toLocaleTimeString(),
dbg_tz: this.session_start.getTimezoneOffset(), dbg_tz: this.session_start.getTimezoneOffset(),
dbg_kind: 'debug', dbg_kind: 'debug',
dbg_device_api: this.device_api_level, dbg_device_api: this.device_api_level,
@@ -817,7 +813,6 @@ class AndroidDebugSession extends DebugSession {
D('disconnectRequest'); D('disconnectRequest');
this._isDisconnecting = true; this._isDisconnecting = true;
analytics.event('debug-end', { analytics.event('debug-end', {
dbg_session_id: this.session_id,
dbg_elapsed: Math.trunc((Date.now() - this.session_start.getTime())/1e3), dbg_elapsed: Math.trunc((Date.now() - this.session_start.getTime())/1e3),
dbg_kind: this.debug_mode, dbg_kind: this.debug_mode,
dbg_term_reason: this.terminate_reason, dbg_term_reason: this.terminate_reason,