Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #323 from nearprotocol/metrics-events
Browse files Browse the repository at this point in the history
Metrics events - add utils to support mixpanel integration and persisting user settings in shell.
  • Loading branch information
janedegtiareva authored Apr 24, 2020
2 parents d4168d5 + 80caf92 commit 92fee29
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 2 deletions.
3 changes: 3 additions & 0 deletions commands/create-account.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const exitOnError = require('../utils/exit-on-error');
const connect = require('../utils/connect');
const { KeyPair } = require('near-api-js');
const eventtracking = require('../utils/eventtracking');

module.exports = {
command: 'create_account <accountId>',
Expand Down Expand Up @@ -31,6 +32,7 @@ module.exports = {
};

async function createAccount(options) {
await eventtracking.track(eventtracking.EVENT_ID_CREATE_ACCOUNT_START, {});
// NOTE: initialBalance is passed as part of config here, parsed in middleware/initial-balance
let near = await connect(options);
let keyPair;
Expand All @@ -46,4 +48,5 @@ async function createAccount(options) {
await near.connection.signer.keyStore.setKey(options.networkId, options.accountId, keyPair);
}
console.log(`Account ${options.accountId} for network "${options.networkId}" was created.`);
await eventtracking.track(eventtracking.EVENT_ID_CREATE_ACCOUNT_SUCCESS, {});
}
3 changes: 3 additions & 0 deletions commands/tx-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const exitOnError = require('../utils/exit-on-error');
const connect = require('../utils/connect');
const inspectResponse = require('../utils/inspect-response');
const bs58 = require('bs58');
const eventtracking = require('../utils/eventtracking');

module.exports = {
command: 'tx-status <hash>',
Expand All @@ -13,6 +14,7 @@ module.exports = {
required: true
}),
handler: exitOnError(async (argv) => {
await eventtracking.track(eventtracking.EVENT_ID_TX_STATUS_START, {});
const near = await connect(argv);

const hashParts = argv.hash.split(':');
Expand All @@ -33,5 +35,6 @@ module.exports = {
const status = await near.connection.provider.txStatus(bs58.decode(hash), accountId);
console.log(`Transaction ${accountId}:${hash}`);
console.log(inspectResponse(status));
await eventtracking.track(eventtracking.EVENT_ID_TX_STATUS_SUCCESS, {});
})
};
9 changes: 7 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const verify = require('./utils/verify-account');
const capture = require('./utils/capture-login-success');

const inspectResponse = require('./utils/inspect-response');
const eventtracking = require('./utils/eventtracking');

// TODO: Fix promisified wrappers to handle error properly

Expand Down Expand Up @@ -100,7 +101,6 @@ exports.login = async function(options) {
input: process.stdin,
output: process.stdout
});

const getAccountFromConsole = async () => {
return await new Promise((resolve) => {
rl.question(
Expand Down Expand Up @@ -128,7 +128,6 @@ exports.login = async function(options) {
}
rl.close();
capture.cancel();

// verify the accountId if we captured it or ...
try {
await verify(accountId, keyPair, options);
Expand All @@ -139,6 +138,7 @@ exports.login = async function(options) {
};

exports.viewAccount = async function(options) {
await eventtracking.track(eventtracking.EVENT_ID_ACCOUNT_STATE_START, {});
let near = await connect(options);
let account = await near.account(options.accountId);
let state = await account.state();
Expand All @@ -147,23 +147,28 @@ exports.viewAccount = async function(options) {
}
console.log(`Account ${options.accountId}`);
console.log(inspectResponse(state));
await eventtracking.track(eventtracking.EVENT_ID_ACCOUNT_STATE_SUCCESS, {});
};

exports.deleteAccount = async function(options) {
await eventtracking.track(eventtracking.EVENT_ID_DELETE_ACCOUNT_START, {});
console.log(
`Deleting account. Account id: ${options.accountId}, node: ${options.nodeUrl}, helper: ${options.helperUrl}, beneficiary: ${options.beneficiaryId}`);
const near = await connect(options);
const account = await near.account(options.accountId);
await account.deleteAccount(options.beneficiaryId);
console.log(`Account ${options.accountId} for network "${options.networkId}" was deleted.`);
await eventtracking.track(eventtracking.EVENT_ID_DELETE_ACCOUNT_SUCCESS, {});
};

exports.keys = async function(options) {
await eventtracking.track(eventtracking.EVENT_ID_ACCOUNT_KEYS_START, {});
let near = await connect(options);
let account = await near.account(options.accountId);
let accessKeys = await account.getAccessKeys();
console.log(`Keys for account ${options.accountId}`);
console.log(inspectResponse(accessKeys));
await eventtracking.track(eventtracking.EVENT_ID_ACCOUNT_KEYS_SUCCESS, {});
};

exports.sendMoney = async function(options) {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@
"flagged-respawn": "^1.0.1",
"is-ci": "^2.0.0",
"jest-environment-node": "^25.1.0",
"mixpanel": "^0.11.0",
"ncp": "^2.0.0",
"near-api-js": "^0.23.1",
"open": "^7.0.1",
"rimraf": "^3.0.0",
"stoppable": "^1.1.0",
"tcp-port-used": "^1.0.1",
"update-notifier": "^4.0.0",
"uuid": "^7.0.3",
"v8flags": "^3.1.3",
"yargs": "^15.0.1"
},
Expand Down
2 changes: 2 additions & 0 deletions test/index.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/bin/bash
export NODE_ENV=${NODE_ENV:-test}
OVERALL_RESULT=0
mkdir ~/.near-config
echo '{"trackingEnabled":false}' > ~/.near-config/settings.json
for test in ./test/test_*; do
echo ""
echo "Running $test"
Expand Down
85 changes: 85 additions & 0 deletions utils/eventtracking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const MIXPANEL_TOKEN = '9aa8926fbcb03eb5d6ce787b5e8fa6eb';
var mixpanel = require('mixpanel').init(MIXPANEL_TOKEN);

const uuid = require('uuid');
const chalk = require('chalk'); // colorize output
const readline = require('readline');
const settings = require('./settings');

const TRACKING_ENABLED_KEY = 'trackingEnabled';
const TRACKING_SESSION_ID_KEY = 'trackingSessionId';

const track = async (eventType, eventProperties) => {
const shellSettings = settings.getShellSettings();
// if the appropriate option is not in settings, ask now and save settings.
if (!(TRACKING_ENABLED_KEY in shellSettings)) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const getEventTrackingConsent = async () => {
for (var attempts = 0; attempts < 10; attempts++) {
const answer = await new Promise((resolve) => {

rl.question(
chalk`We would like to collect data on near-shell usage to improve developer experience.` +
chalk ` We will never send private information. We only collect which commands are run via an anonymous identifier.` +
chalk`{bold.yellow Would you like to opt in (y/n)?}`,
async (consentToEventTracking) => {
if (consentToEventTracking == 'y' || consentToEventTracking == 'Y') {
resolve(true);
}
else if (consentToEventTracking == 'n' || consentToEventTracking == 'N') {
resolve(false);
}
resolve(undefined);
});
});
if (answer !== undefined) {
return answer;
}
}
return false; // If they can't figure it out in this many attempts, just opt out
};

shellSettings[TRACKING_ENABLED_KEY] = await getEventTrackingConsent();
shellSettings[TRACKING_SESSION_ID_KEY] = shellSettings[TRACKING_ENABLED_KEY] ? uuid.v4() : undefined;
rl.close();
settings.saveShellSettings(shellSettings);
}

if (!shellSettings[TRACKING_ENABLED_KEY]) {
return;
}

try {
const mixPanelProperties = {
distinct_id: shellSettings[TRACKING_SESSION_ID_KEY]
};
Object.assign(mixPanelProperties, eventProperties);
mixpanel.track(eventType, mixPanelProperties);
}
catch (e) {
console.log('Warning: problem while sending developer event tracking data. This is not critical. Error: ', e);
}
};

module.exports = {
track,

// Event ids used in mixpanel. Note that we want to mention shell to make it very easy to tell that an event came from shell,
// since mixpanel might be used for other components as well.
EVENT_ID_ACCOUNT_STATE_START: 'shell_account_state_start',
EVENT_ID_ACCOUNT_STATE_SUCCESS: 'shell_account_state_success',
EVENT_ID_DELETE_ACCOUNT_START: 'shell_delete_account_start',
EVENT_ID_DELETE_ACCOUNT_SUCCESS: 'shell_delete_account_success',
EVENT_ID_ACCOUNT_KEYS_START: 'shell_account_keys_start',
EVENT_ID_ACCOUNT_KEYS_SUCCESS: 'shell_account_keys_success',
EVENT_ID_TX_STATUS_START: 'shell_tx_status_start',
EVENT_ID_TX_STATUS_SUCCESS: 'shell_tx_status_success',
EVENT_ID_LOGIN: 'shell_login',
EVENT_ID_DEPLOY: 'shell_deploy',
EVENT_ID_DEV_DEPLOY: 'shell_dev_deploy',
EVENT_ID_CREATE_ACCOUNT_START: 'shell_create_account_start',
EVENT_ID_CREATE_ACCOUNT_SUCCESS: 'shell_create_account_success'
};
44 changes: 44 additions & 0 deletions utils/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const fs = require('fs');
const homedir = require('os').homedir();
const path = require('path');


// Persistent shell settings
const SETTINGS_FILE_NAME = 'settings.json';
const SETTINGS_DIR = '.near-config';

const getShellSettings = () => {
const nearPath = path.join(homedir, SETTINGS_DIR);
try {
if (!fs.existsSync(nearPath)) {
fs.mkdirSync(nearPath);
}
const shellSettingsPath = path.join(nearPath, SETTINGS_FILE_NAME);
if (!fs.existsSync(shellSettingsPath)) {
return {};
} else {
return JSON.parse(fs.readFileSync(shellSettingsPath, 'utf8'));
}
} catch (e) {
console.log(e);
}
return {};
};

const saveShellSettings = (settings) => {
const nearPath = path.join(homedir, SETTINGS_DIR);
try {
if (!fs.existsSync(nearPath)) {
fs.mkdirSync(nearPath);
}
const shellSettingsPath = path.join(nearPath, SETTINGS_FILE_NAME);
fs.writeFileSync(shellSettingsPath, JSON.stringify(settings));
} catch (e) {
console.log(e);
}
};

module.exports = {
getShellSettings,
saveShellSettings
};
46 changes: 46 additions & 0 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 92fee29

Please sign in to comment.