From 75f22c02091ade1bcacadd484828291e0d91f619 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 29 Feb 2016 15:58:10 -0400 Subject: [PATCH] Implement AnalyticsService.logEvent() --- lib/browser/app.js | 30 +++++++++++++------- lib/browser/modules/analytics.js | 48 +++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/lib/browser/app.js b/lib/browser/app.js index 4247ab60..5f818443 100644 --- a/lib/browser/app.js +++ b/lib/browser/app.js @@ -46,14 +46,14 @@ const app = angular.module('Etcher', [ 'Etcher.analytics' ]); -app.controller('AppController', function($q, $log, DriveScannerService, SelectionStateService, ImageWriterService, AnalyticsService) { +app.controller('AppController', function($q, DriveScannerService, SelectionStateService, ImageWriterService, AnalyticsService) { let self = this; this.selection = SelectionStateService; this.writer = ImageWriterService; this.scanner = DriveScannerService; this.restart = function(options) { - AnalyticsService.log('Restarting'); + AnalyticsService.logEvent('Restart'); this.selection.clear(options); self.state = { @@ -75,7 +75,9 @@ app.controller('AppController', function($q, $log, DriveScannerService, Selectio // `angular.equals` is used instead of `_.isEqual` to // cope with `$$hashKey`. if (!angular.equals(self.selection.getDrive(), drive)) { - AnalyticsService.log(`Autoselecting drive: ${drive.device}`); + AnalyticsService.logEvent('Auto-select drive', { + device: drive.device + }); self.selectDrive(drive); } @@ -99,13 +101,17 @@ app.controller('AppController', function($q, $log, DriveScannerService, Selectio this.selectImage = function() { return $q.when(dialog.selectImage()).then(function(image) { self.selection.setImage(image); - AnalyticsService.log(`Image selected: ${image}`); + AnalyticsService.logEvent('Select image', { + image: image + }); }); }; this.selectDrive = function(drive) { self.selection.setDrive(drive); - AnalyticsService.log(`Drive selected: ${drive.device}`); + AnalyticsService.logEvent('Select drive', { + device: drive.device + }); }; this.reselectImage = function() { @@ -119,7 +125,7 @@ app.controller('AppController', function($q, $log, DriveScannerService, Selectio // "returns" to the first step. self.selection.clear(); - AnalyticsService.log('Reselecting image'); + AnalyticsService.logEvent('Reselect image'); }; this.reselectDrive = function() { @@ -128,7 +134,7 @@ app.controller('AppController', function($q, $log, DriveScannerService, Selectio } self.selection.removeDrive(); - AnalyticsService.log('Reselecting drive'); + AnalyticsService.logEvent('Reselect drive'); }; this.burn = function(image, drive) { @@ -137,16 +143,20 @@ app.controller('AppController', function($q, $log, DriveScannerService, Selectio // otherwise Windows throws EPERM self.scanner.stop(); - AnalyticsService.log(`Burning ${image} to ${drive.device}`); + AnalyticsService.logEvent('Burn', { + image: image, + device: drive.device + }); + return self.writer.burn(image, drive, function(state) { self.state = state; - $log.debug(`Progress: ${self.state.progress}% at ${self.state.speed} MB/s`); + AnalyticsService.log(`Progress: ${self.state.progress}% at ${self.state.speed} MB/s`); // Show progress inline in operating system task bar currentWindow.setProgressBar(self.state.progress / 100); }).then(function() { - AnalyticsService.log('Done!'); + AnalyticsService.logEvent('Done'); }).catch(dialog.showError).finally(function() { // Remove progress bar from task bar diff --git a/lib/browser/modules/analytics.js b/lib/browser/modules/analytics.js index 4de40a77..b5775670 100644 --- a/lib/browser/modules/analytics.js +++ b/lib/browser/modules/analytics.js @@ -20,6 +20,7 @@ * @module Etcher.analytics */ +const _ = require('lodash'); const angular = require('angular'); const username = require('username'); const app = require('electron').remote.app; @@ -38,8 +39,14 @@ analytics.config(function($mixpanelProvider) { $mixpanelProvider.apiKey('63e5fc4563e00928da67d1226364dd4c'); $mixpanelProvider.superProperties({ + + // jscs:disable requireCamelCaseOrUpperCaseIdentifiers + distinct_id: username.sync(), - version: app.getVersion(), + + // jscs:enable requireCamelCaseOrUpperCaseIdentifiers + + electron: app.getVersion(), node: process.version, arch: process.arch }); @@ -71,11 +78,15 @@ analytics.config(function($provide) { }); analytics.service('AnalyticsService', function($log, $mixpanel) { + let self = this; /** - * @summary Log an event + * @summary Log a debug message * @function - * @private + * @public + * + * @description + * This function sends the debug message to TrackJS only. * * @param {String} message - message * @@ -83,8 +94,37 @@ analytics.service('AnalyticsService', function($log, $mixpanel) { * AnalyticsService.log('Hello World'); */ this.log = function(message) { - $mixpanel.track(message); $log.debug(message); }; + /** + * @summary Log an event + * @function + * @public + * + * @description + * This function sends the debug message to TrackJS and Mixpanel. + * + * @param {String} message - message + * @param {Object} [data] - event data + * + * @example + * AnalyticsService.logEvent('Select image', { + * image: '/dev/disk2' + * }); + */ + this.logEvent = function(message, data) { + + // Clone data before passing it to `mixpanel.track` + // since this function mutates the object adding + // some custom private Mixpanel properties. + $mixpanel.track(message, _.clone(data)); + + if (data) { + message += ` (${JSON.stringify(data)})`; + } + + self.log(message); + }; + });