From 58b0d6320ab2ac4bad7379a8eb6dacaef6b7f386 Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Wed, 2 Nov 2016 21:00:11 -0700 Subject: [PATCH] Client stats factory and usage - Add a new factory for the client stats - Use it to define client time, event and error methods - Log a stat every time we switch tabs (example of client_time) - Log errors in the tab switching (example of client_error) - Log when we forced sync (example of client_nav_event) - Add the new factory to index.html! Related usercache code is https://github.com/e-mission/cordova-usercache/commit/67ae0c9d8d6fe454d3dfded1a46d95b262f75aac server code is https://github.com/e-mission/e-mission-server/commit/7487c82578e8933f4da8f9d3fa3522c102906c81 --- www/index.html | 1 + www/js/control.js | 13 ++++-- www/js/controllers.js | 10 ++++- www/js/stats/clientstats.js | 79 +++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 www/js/stats/clientstats.js diff --git a/www/index.html b/www/index.html index 3d852b3ae..6cf9ff064 100644 --- a/www/index.html +++ b/www/index.html @@ -62,6 +62,7 @@ + diff --git a/www/js/control.js b/www/js/control.js index 5ba49511c..a82e06751 100644 --- a/www/js/control.js +++ b/www/js/control.js @@ -4,12 +4,13 @@ angular.module('emission.main.control',['emission.services', 'emission.splash.startprefs', 'emission.splash.updatecheck', 'emission.main.metrics.factory', + 'emission.stats.clientstats', 'angularLocalStorage']) .controller('ControlCtrl', function($scope, $window, $ionicScrollDelegate, $state, $ionicPopup, $ionicActionSheet, $ionicPopover, - $rootScope, storage, StartPrefs, ControlHelper, UpdateCheck, - CalorieCal) { + $rootScope, storage, StartPrefs, ControlHelper, UpdateCheck, + CalorieCal, ClientStats) { $scope.emailLog = ControlHelper.emailLog; $scope.dark_theme = $rootScope.dark_theme; $scope.userData = [] @@ -174,7 +175,7 @@ angular.module('emission.main.control',['emission.services', $scope.showMap = function() { $state.go("root.main.map"); } - $scope.getState = function() { + $scope.getState = function() { ControlHelper.getState().then(function(response) { $scope.$apply(function() { $scope.settings.collect.state = response; @@ -187,7 +188,7 @@ angular.module('emission.main.control',['emission.services', $scope.nukeUserCache = function() { $ionicPopup.alert({template: "WATCH OUT! If there is unsynced data, you may lose it. If you want to keep the data, use 'Force Sync' before doing this"}) .then(function(result) { - if (result) { + if (result) { storage.clearAll(); window.cordova.plugins.BEMUserCache.clearAll() .then(function(result) { @@ -255,6 +256,10 @@ angular.module('emission.main.control',['emission.services', }; $scope.forceSync = function() { + ClientStats.addEvent(ClientStats.getStatKeys().BUTTON_FORCE_SYNC).then( + function() { + console.log("Added "+ClientStats.getStatKeys().BUTTON_FORCE_SYNC+" event"); + }); ControlHelper.forceSync().then(function(response) { $ionicPopup.alert({template: 'success -> '+response}); }, function(error) { diff --git a/www/js/controllers.js b/www/js/controllers.js index 07def9f84..2c4e76e24 100644 --- a/www/js/controllers.js +++ b/www/js/controllers.js @@ -3,6 +3,7 @@ angular.module('emission.controllers', ['emission.splash.updatecheck', 'emission.splash.startprefs', 'emission.splash.referral', + 'emission.stats.clientstats', 'customURLScheme']) .controller('RootCtrl', function($scope) {}) @@ -10,11 +11,12 @@ angular.module('emission.controllers', ['emission.splash.updatecheck', .controller('DashCtrl', function($scope) {}) .controller('SplashCtrl', function($scope, $state, $interval, $rootScope, - CustomURLScheme, UpdateCheck, StartPrefs, ReferralHandler) { + CustomURLScheme, UpdateCheck, StartPrefs, ReferralHandler, ClientStats) { console.log('SplashCtrl invoked'); // alert("attach debugger!"); CustomURLScheme.onLaunch(function(event, url){ console.log("GOT URL:"+url); + var kvList = ReferralHandler.parseURL(url); // There are 3 types of users in total if (kvList.route == 'join') { @@ -35,16 +37,22 @@ angular.module('emission.controllers', ['emission.splash.updatecheck', UpdateCheck.checkForUpdates(); $rootScope.checkedForUpdates = true; } */ + ClientStats.addReading(ClientStats.getStatKeys().STATE_CHANGED, + fromState.name + '-2-' + toState.name).then(function() {}, function() {}); }); $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){ console.log("Error "+error+" while changing state from "+JSON.stringify(fromState) +" to "+JSON.stringify(toState)); + ClientStats.addError(ClientStats.getStatKeys().STATE_CHANGED, + fromState.name + '-2-' + toState.name+ "_" + error).then(function() {}, function() {}); }); $rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){ console.log("unfoundState.to = "+unfoundState.to); // "lazy.state" console.log("unfoundState.toParams = " + unfoundState.toParams); // {a:1, b:2} console.log("unfoundState.options = " + unfoundState.options); // {inherit:false} + default options + ClientStats.addError(ClientStats.getStatKeys().STATE_CHANGED, + fromState.name + '-2-' + unfoundState.name).then(function() {}, function() {}); }); var isInList = function(element, list) { diff --git a/www/js/stats/clientstats.js b/www/js/stats/clientstats.js new file mode 100644 index 000000000..3e5a4b3b4 --- /dev/null +++ b/www/js/stats/clientstats.js @@ -0,0 +1,79 @@ +'use strict'; + +angular.module('emission.stats.clientstats', []) + +.factory('ClientStats', function($window) { + var clientStat = {}; + + clientStat.CLIENT_TIME = "stats/client_time"; + clientStat.CLIENT_ERROR = "stats/client_error"; + clientStat.CLIENT_NAV_EVENT = "stats/client_nav_event"; + + clientStat.getStatKeys = function() { + return { + STATE_CHANGED: "state_changed", + BUTTON_FORCE_SYNC: "button_sync_forced" + }; + } + + clientStat.getDB = function() { + if (angular.isDefined($window) && angular.isDefined($window.cordova) && + angular.isDefined($window.cordova.plugins)) { + return $window.cordova.plugins.BEMUserCache; + } else { + return; // undefined + } + } + + clientStat.getAppVersion = function() { + if (angular.isDefined(clientStat.appVersion)) { + return clientStat.appVersion; + } else { + if (angular.isDefined($window) && angular.isDefined($window.cordova) && + angular.isDefined($window.cordova.getAppVersion)) { + $window.cordova.getAppVersion.getVersionNumber().then(function(version) { + clientStat.appVersion = version; + }); + } + return; + } + } + + clientStat.getStatsEvent = function(name, reading) { + var ts_sec = Date.now() / 1000; + var appVersion = clientStat.getAppVersion(); + return { + 'name': name, + 'ts': ts_sec, + 'reading': reading, + 'client_app_version': appVersion, + 'client_os_version': $window.device.version + }; + } + clientStat.addReading = function(name, reading) { + var db = clientStat.getDB(); + if (angular.isDefined(db)) { + return db.putMessage(clientStat.CLIENT_TIME, + clientStat.getStatsEvent(name, reading)); + } + } + + clientStat.addEvent = function(name) { + var db = clientStat.getDB(); + if (angular.isDefined(db)) { + return db.putMessage(clientStat.CLIENT_NAV_EVENT, + clientStat.getStatsEvent(name, null)); + } + } + + clientStat.addError = function(name, errorStr) { + var db = clientStat.getDB(); + if (angular.isDefined(db)) { + return db.putMessage(clientStat.CLIENT_ERROR, + clientStat.getStatsEvent(name, errorStr)); + } + } + + return clientStat; +}) +