diff options
Diffstat (limited to 'www')
| -rw-r--r-- | www/index.html | 14 | ||||
| -rw-r--r-- | www/js/DataModel.js | 42 | ||||
| -rw-r--r-- | www/js/EventCtrl.js | 3 | ||||
| -rw-r--r-- | www/js/EventsGraphsCtrl.js | 2 | ||||
| -rw-r--r-- | www/js/HelpCtrl.js | 3 | ||||
| -rw-r--r-- | www/js/LogCtrl.js | 61 | ||||
| -rw-r--r-- | www/js/LoginCtrl.js | 2 | ||||
| -rw-r--r-- | www/js/ModalCtrl.js | 1 | ||||
| -rw-r--r-- | www/js/MonitorCtrl.js | 3 | ||||
| -rw-r--r-- | www/js/MontageCtrl.js | 2 | ||||
| -rw-r--r-- | www/js/StateCtrl.js | 4 | ||||
| -rw-r--r-- | www/js/app.js | 22 | ||||
| -rw-r--r-- | www/lib/filelogger/.bower.json | 40 | ||||
| -rw-r--r-- | www/lib/filelogger/LICENSE | 21 | ||||
| -rw-r--r-- | www/lib/filelogger/README.md | 123 | ||||
| -rw-r--r-- | www/lib/filelogger/bower.json | 30 | ||||
| -rw-r--r-- | www/lib/filelogger/dist/filelogger.js | 274 | ||||
| -rw-r--r-- | www/lib/filelogger/dist/filelogger.min.js | 6 | ||||
| -rw-r--r-- | www/lib/filelogger/package.json | 26 | ||||
| -rw-r--r-- | www/templates/log.html | 16 |
20 files changed, 688 insertions, 7 deletions
diff --git a/www/index.html b/www/index.html index 65f0e1cd..374862fd 100644 --- a/www/index.html +++ b/www/index.html @@ -27,15 +27,16 @@ error interceptor in app.js --> <script src="lib/ionic/js/ionic.bundle.min.js"></script> + <script src="lib/ngCordova/dist/ng-cordova.min.js"></script> + <script src="lib/filelogger/dist/filelogger.min.js"></script> <!-- cordova script (this will be a 404 during development) --> <script src="cordova.js"></script> - <script src="lib/ngCordova/dist/ng-cordova.min.js"></script> + <!-- your app's js --> - <script src="js/templates.js"></script> <script src="js/app.js"></script> <script src="js/controllers.js"></script> @@ -49,6 +50,7 @@ <script src="js/HelpCtrl.js"></script> <script src="js/StateCtrl.js"></script> <script src="js/DevOptionsCtrl.js"></script> + <script src="js/LogCtrl.js"></script> <script src="lib/angular-circular-navigation/angular-circular-navigation.js"></script> @@ -134,6 +136,14 @@ <i class="icon ion-help"></i> </span> Help </ion-item> + + <ion-item nav-clear menu-close href="#/log"> + <span class=" item-icon-left"> + <i class="icon ion-clipboard"></i> + </span> Logs + </ion-item> + + </ion-list> </ion-content> </ion-side-menu> diff --git a/www/js/DataModel.js b/www/js/DataModel.js index d1470685..bfd81b74 100644 --- a/www/js/DataModel.js +++ b/www/js/DataModel.js @@ -7,7 +7,7 @@ // that many other controllers use // It's grown over time. I guess I may have to split this into multiple services in the future -angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ionicLoading', '$ionicBackdrop', function ($http, $q, $ionicLoading, $ionicBackdrop) { +angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ionicLoading', '$ionicBackdrop', '$fileLogger', function ($http, $q, $ionicLoading, $ionicBackdrop,$fileLogger) { var monitorsLoaded = 0; var montageSize = 3; @@ -26,8 +26,28 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion 'keepAwake':true // don't dim/dim during live view }; + //-------------------------------------------------------------------------- + // uses fileLogger to write logs to file for later investigation + //-------------------------------------------------------------------------- + function zmLog(val,logtype) + { + $fileLogger.log(logtype, val); + } + return { + //------------------------------------------------------------- + // used by various controllers to log messages to file + //------------------------------------------------------------- + + zmLog: function (val,type) { + var logtype = 'info'; + if (type != undefined) + logtype = type ; + zmLog(val,logtype); + + }, + // This function is called when the app is ready to run // sets up various variables // including persistent login data for the ZM apis and portal @@ -36,10 +56,17 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion // the ZM portal authentication, which is pretty messy. But unless // the ZM authors fix this and streamline the access of images // from APIs, I don't have an option - init: function () { console.log("****** DATAMODEL INIT SERVICE CALLED ********"); + zmLog("ZMData init: checking for stored variables & setting up log file"); + + $fileLogger.setStorageFilename('zmNinjaLog.txt'); + + $fileLogger.deleteLogfile().then(function() { + console.log('Logfile deleted'); + }); + if (window.localStorage.getItem("username") != undefined) { loginData.username = window.localStorage.getItem("username"); @@ -140,6 +167,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion console.log ("**** setAwake called with:" + val); + zmLog("Switching screen always on to " + val); if (val) { @@ -170,7 +198,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion setLogin: function (newLogin) { loginData = newLogin; - + zmLog("Saving all parameters to storage"); window.localStorage.setItem("username", loginData.username); window.localStorage.setItem("password", loginData.password); window.localStorage.setItem("url", loginData.url); @@ -222,6 +250,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion if ((monitorsLoaded == 0) || (forceReload == 1)) // monitors are empty or force reload { console.log("ZMDataModel: Invoking HTTP get to load monitors"); + zmLog ( (forceReload==1)? "getMonitors:Force reloading all monitors" : "getMonitors:Loading all monitors"); var apiurl = loginData.apiurl; var myurl = apiurl + "/monitors.json"; $http.get(myurl /*,{timeout:15000}*/ ) @@ -232,9 +261,11 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion monitorsLoaded = 1; d.resolve(monitors); $ionicLoading.hide(); + zmLog ("Monitor load was successful, loaded " + monitors.length + " monitors"); }) .error(function (err) { console.log("HTTP Error " + err); + zmLog ("Monitor load failed " + JSON.stringify(err), "error"); // To keep it simple for now, I'm translating an error // to imply no monitors could be loaded. FIXME: conver to proper error monitors = []; @@ -248,6 +279,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion } else // monitors are loaded { console.log("Returning pre-loaded list of " + monitors.length + " monitors"); + zmLog("Returning pre-loaded list of " + monitors.length + " monitors"); d.resolve(monitors); $ionicLoading.hide(); return d.promise; @@ -285,6 +317,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion }) .error(function (error) { console.log("*** ERROR GETTING TOTAL PAGES ***"); + zmLog ("Error retrieving page count of events " + JSON.stringify(error), "error"); d.reject(error); return d.promise; }); @@ -349,6 +382,7 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion .error(function (err) { if (loadingStr != 'none') $ionicLoading.hide(); console.log("HTTP Events error " + err); + zmLog("Error fetching events for page " + pageId + " Err: " + JSON.stringify(err), "error"); // I need to reject this as I have infinite scrolling // implemented in EventCtrl.js --> and if it does not know // it got an error going to the next page, it will get into @@ -379,6 +413,8 @@ angular.module('zmApp.controllers').service('ZMDataModel', ['$http', '$q', '$ion montageSize = montage; }, + + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- diff --git a/www/js/EventCtrl.js b/www/js/EventCtrl.js index 284c0147..e4ac3516 100644 --- a/www/js/EventCtrl.js +++ b/www/js/EventCtrl.js @@ -208,7 +208,7 @@ angular.module('zmApp.controllers').controller('zmApp.EventCtrl', ['$ionicPlatfo //-------------------------------------------------------- this.pollEventsProgress = function() { - console.log ("**************"); + // console.log ("**************"); }; //-------------------------------------------------------- @@ -322,6 +322,7 @@ angular.module('zmApp.controllers').controller('zmApp.EventCtrl', ['$ionicPlatfo req.error(function (resp) { console.log("ERROR: " + JSON.stringify(resp)); + ZMDataModel.zmLog("Error sending event command " +JSON.stringify(resp), "error"); }); }; diff --git a/www/js/EventsGraphsCtrl.js b/www/js/EventsGraphsCtrl.js index 92bc870a..ca2653d3 100644 --- a/www/js/EventsGraphsCtrl.js +++ b/www/js/EventsGraphsCtrl.js @@ -81,6 +81,7 @@ angular.module('zmApp.controllers').controller('zmApp.EventsGraphsCtrl', ['$ioni endDate = cur.format("YYYY-MM-DD hh:mm:ss"); startDate = cur.subtract(hrs, 'hours').format("YYYY-MM-DD hh:mm:ss"); console.log("Start and End " + startDate + "==" + endDate); + ZMDataModel.zmLog("Generating graph for " + startDate + " to " + endDate); } @@ -139,6 +140,7 @@ angular.module('zmApp.controllers').controller('zmApp.EventsGraphsCtrl', ['$ioni // but what I am really doing now is treating it like no events // works but TBD: make this into a proper error handler $scope.data.datasets[0].data[j] = 0; + ZMDataModel.zmLog ("Error retrieving events for graph " + JSON.stringify(data), "error"); }); })(i); // j } //for diff --git a/www/js/HelpCtrl.js b/www/js/HelpCtrl.js index 89c2171b..270cbf33 100644 --- a/www/js/HelpCtrl.js +++ b/www/js/HelpCtrl.js @@ -8,6 +8,8 @@ $scope.openMenu = function () { }; + + //------------------------------------------------------------------------- // Lets make sure we set screen dim properly as we enter // The problem is we enter other states before we leave previous states @@ -18,6 +20,7 @@ $scope.openMenu = function () { $scope.$on('$ionicView.enter', function () { console.log("**VIEW ** Help Ctrl Entered"); ZMDataModel.setAwake(false); + }); }]); diff --git a/www/js/LogCtrl.js b/www/js/LogCtrl.js new file mode 100644 index 00000000..1ac903a7 --- /dev/null +++ b/www/js/LogCtrl.js @@ -0,0 +1,61 @@ +/* jshint -W041 */ +/* jslint browser: true*/ +/* global cordova,StatusBar,angular,console */ + +angular.module('zmApp.controllers').controller('zmApp.LogCtrl', ['$scope', '$rootScope', '$ionicModal', 'ZMDataModel', '$ionicSideMenuDelegate', '$fileLogger', '$cordovaEmailComposer', function ($scope, $rootScope, $ionicModal, ZMDataModel, $ionicSideMenuDelegate, $fileLogger, $cordovaEmailComposer) { + $scope.openMenu = function () { + $ionicSideMenuDelegate.toggleLeft(); + }; + + + //-------------------------------------------------------------------------- + // Convenience function to send logs via email + //-------------------------------------------------------------------------- + $scope.sendEmail = function (logstring) { + if (window.cordova) { + // pass= password= should be replaced + //logstring = logstring.replace(/password=*?/g, 'password=xxxx' + $cordovaEmailComposer.isAvailable().then(function () { + var email = { + to: '', + subject: 'zmNinja Logs', + body: logstring, + isHtml: false + }; + $cordovaEmailComposer.open(email); + }, function () { + ZMDataModel.zmLog("Email plugin not found", "error"); + }); + } else { + console.log("Skipping email module as cordova does not exist"); + } + + }; + + //------------------------------------------------------------------------- + // Lets make sure we set screen dim properly as we enter + // The problem is we enter other states before we leave previous states + // from a callback perspective in ionic, so we really can't predictably + // reset power state on exit as if it is called after we enter another + // state, that effectively overwrites current view power management needs + //------------------------------------------------------------------------ + $scope.$on('$ionicView.enter', function () { + console.log("**VIEW ** Log Ctrl Entered"); + ZMDataModel.setAwake(false); + + $scope.zmLog = { + logString: "" + }; + $fileLogger.getLogfile().then(function (l) { + + $scope.zmLog.logString = l; + //console.log ("LOGS" + logstring); + }, + function (error) { + $scope.zmLog.logString = "Error getting log: " + JSON.stringify(error); + }); + + + }); + +}]); diff --git a/www/js/LoginCtrl.js b/www/js/LoginCtrl.js index 1da2f83d..4bf04285 100644 --- a/www/js/LoginCtrl.js +++ b/www/js/LoginCtrl.js @@ -138,6 +138,7 @@ function addhttp(url) { }, function (error) { $ionicLoading.hide(); + ZMDataModel.zmLog("Settings check error: " +JSON.stringify(error),"error"); //alert("Error string" + JSON.stringify(error)); $ionicPopup.show({ @@ -155,6 +156,7 @@ function addhttp(url) { title: 'Error Details', template: JSON.stringify(error) }); + } } ] diff --git a/www/js/ModalCtrl.js b/www/js/ModalCtrl.js index d8f61b03..a9c45c34 100644 --- a/www/js/ModalCtrl.js +++ b/www/js/ModalCtrl.js @@ -203,6 +203,7 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco req.error(function (resp) { $ionicLoading.hide(); console.log("ERROR: " + JSON.stringify(resp)); + ZMDataModel.zmLog("Error sending PTZ:" + JSON.stringify(resp), "error"); }); } diff --git a/www/js/MonitorCtrl.js b/www/js/MonitorCtrl.js index ee9605fc..bf94f48f 100644 --- a/www/js/MonitorCtrl.js +++ b/www/js/MonitorCtrl.js @@ -231,10 +231,13 @@ angular.module('zmApp.controllers').controller('zmApp.MonitorCtrl', ['$ionicPopu .success(function(data) { $scope.ptzMoveCommand = (data.control.Control.CanMoveCon == '1')? 'moveCon':'move'; console.log("***moveCommand: " +$scope.ptzMoveCommand ); + ZMDataModel.zmLog ("ControlDB reports PTZ command to be " + $scope.ptzMoveCommand ); }) .error(function(data) { console.log ("** Error retrieving move PTZ command"); + ZMDataModel.zmLog ("Error retrieving PTZ command " + JSON.stringify(data),"error"); }); + } diff --git a/www/js/MontageCtrl.js b/www/js/MontageCtrl.js index bd2ab1ef..b95d2553 100644 --- a/www/js/MontageCtrl.js +++ b/www/js/MontageCtrl.js @@ -146,9 +146,11 @@ angular.module('zmApp.controllers').controller('zmApp.MontageCtrl', ['$scope', ' .success(function(data) { $scope.ptzMoveCommand = (data.control.Control.CanMoveCon == '1')? 'moveCon':'move'; console.log("***moveCommand: " +$scope.ptzMoveCommand ); + ZMDataModel.zmLog ("ControlDB reports PTZ command to be " + $scope.ptzMoveCommand ); }) .error(function(data) { console.log ("** Error retrieving move PTZ command"); + ZMDataModel.zmLog ("Error retrieving PTZ command " + JSON.stringify(data),"error"); }); } diff --git a/www/js/StateCtrl.js b/www/js/StateCtrl.js index ec3a771a..cf6d97d9 100644 --- a/www/js/StateCtrl.js +++ b/www/js/StateCtrl.js @@ -64,6 +64,7 @@ angular.module('zmApp.controllers').controller('zmApp.StateCtrl', ['$ionicPopup' function (error) { $scope.zmDisk = "unknown"; console.log("ERROR:" + JSON.stringify(error)); + ZMDataModel.zmLog("Error retrieving DiskStatus: " + JSON.stringify(error),"error"); } ); } @@ -95,6 +96,7 @@ angular.module('zmApp.controllers').controller('zmApp.StateCtrl', ['$ionicPopup' }, function (error) { console.log("ERROR in getRun: " + JSON.stringify(error)); + ZMDataModel.zmLog("Error getting RunStatus " + JSON.stringify(error),"error"); $scope.color = 'color:red;'; $scope.zmRun = 'undetermined'; } @@ -119,6 +121,7 @@ angular.module('zmApp.controllers').controller('zmApp.StateCtrl', ['$ionicPopup' }, function (error) { console.log("ERROR in getLoad: " + JSON.stringify(error)); + ZMDataModel.zmLog("Error retrieving loadStatus " + JSON.stringify(error),"error"); $scope.zmLoad = 'undetermined'; } ); @@ -176,6 +179,7 @@ angular.module('zmApp.controllers').controller('zmApp.StateCtrl', ['$ionicPopup' //if (error.status) // it seems to return error with status 0 if ok // { console.log("ERROR in Change State:" + JSON.stringify(error)); + ZMDataModel.zmLog("Error in change run state:"+JSON.stringify(error),"error"); $scope.zmRun = 'undetermined'; $scope.color = 'color:orange;'; inProgress = 0; diff --git a/www/js/app.js b/www/js/app.js index ffff0c68..bd21fabe 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -7,6 +7,7 @@ angular.module('zmApp', [ 'ionic', 'zmApp.controllers', + 'fileLogger' ]) //------------------------------------------------------------------ @@ -51,7 +52,7 @@ angular.module('zmApp', [ } else { - console.log ("HTTP INTERCEPT:Skipping HTTP timeout for "+config.url); + //console.log ("HTTP INTERCEPT:Skipping HTTP timeout for "+config.url); } //console.log("*** HTTP URL INTERCEPTOR CALLED with "+config.url+" ***"); return config; @@ -70,6 +71,7 @@ angular.module('zmApp', [ function doLogin() { console.log ("**** ZM AUTO LOGIN CALLED"); + ZMDataModel.zmLog("zmAutologin timer started"); var loginData = ZMDataModel.getLogin(); $http({ method:'POST', @@ -98,10 +100,12 @@ angular.module('zmApp', [ .success(function(data) { console.log ("**** ZM Login OK"); + ZMDataModel.zmLog("zmAutologin successfully logged into Zoneminder"); }) .error(function(error) { console.log ("**** ZM Login FAILED"); + ZMDataModel.zmLog ("zmAutologin Error " + JSON.stringify(error), "error"); }); } @@ -120,6 +124,7 @@ angular.module('zmApp', [ function stop() { $interval.cancel(zmAutoLoginHandle); + ZMDataModel.zmLog("Cancelling zmAutologin timer"); } @@ -166,6 +171,7 @@ angular.module('zmApp', [ var loginData = ZMDataModel.getLogin(); if (ZMDataModel.isLoggedIn()) { + ZMDataModel.zmLog ("User is logged in"); console.log("VALID CREDENTIALS. Grabbing Monitors"); ZMDataModel.getMonitors(0); @@ -179,6 +185,7 @@ angular.module('zmApp', [ $rootScope.devWidth = ((window.innerWidth > 0) ? window.innerWidth : screen.width); $rootScope.devHeight = ((window.innerHeight > 0) ? window.innerHeight : screen.height); console.log("********NEW Computed Dev Width & Height as" + $rootScope.devWidth + "*" + $rootScope.devHeight); + ZMDataModel.zmLog("Device orientation change: "+$rootScope.devWidth + "*" + $rootScope.devHeight); }; window.addEventListener("resize", checkOrientation, false); @@ -211,9 +218,11 @@ angular.module('zmApp', [ $ionicPlatform.ready(function () { // generates and error in desktops but works fine + ZMDataModel.zmLog("Device is ready"); console.log("**** DEVICE READY ***"); + setTimeout(function () { if (window.cordova) { @@ -234,6 +243,7 @@ angular.module('zmApp', [ // from foreground to background and back document.addEventListener("resume", function () { console.log("****The application is resuming from the background"); + ZMDataModel.zmLog("App is resuming from background"); $rootScope.rand = Math.floor((Math.random() * 100000) + 1); console.log("** generated Random of " + $rootScope.rand); $state.go($state.current, {}, { @@ -246,6 +256,7 @@ angular.module('zmApp', [ document.addEventListener("pause", function () { console.log("****The application is going into background"); + ZMDataModel.zmLog("App is going into background"); zmAutoLogin.stop(); }, false); @@ -361,6 +372,15 @@ angular.module('zmApp', [ controller: 'zmApp.DevOptionsCtrl', }) + .state('log', { + data: { + requireLogin: false + }, + url: "/log", + templateUrl: "templates/log.html", + controller: 'zmApp.LogCtrl', + }) + .state('montage', { data: { requireLogin: true diff --git a/www/lib/filelogger/.bower.json b/www/lib/filelogger/.bower.json new file mode 100644 index 00000000..c063767b --- /dev/null +++ b/www/lib/filelogger/.bower.json @@ -0,0 +1,40 @@ +{ + "name": "filelogger", + "version": "1.1.0", + "homepage": "https://github.com/pbakondy/filelogger", + "authors": [ + "Peter Bakondy <pbakondy@gmail.com>" + ], + "description": "Cordova library to log messages to local filesystem", + "main": "./dist/filelogger.min.js", + "ignore": [ + "**/.*", + "gulpfile.js", + "src", + "config" + ], + "dependencies": { + "ngCordova": ">= 0.1.14-alpha" + }, + "keywords": [ + "cordova", + "cordova plugin", + "ionic", + "ionic plugin", + "angular module", + "log", + "logger", + "file logger" + ], + "license": "MIT", + "_release": "1.1.0", + "_resolution": { + "type": "version", + "tag": "v1.1.0", + "commit": "4b5f765cf1737a51cc29bcaeca035d72eb6e8272" + }, + "_source": "git://github.com/pbakondy/filelogger.git", + "_target": "~1.1.0", + "_originalSource": "filelogger", + "_direct": true +} diff --git a/www/lib/filelogger/LICENSE b/www/lib/filelogger/LICENSE new file mode 100644 index 00000000..ec5a3987 --- /dev/null +++ b/www/lib/filelogger/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Bakondy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
\ No newline at end of file diff --git a/www/lib/filelogger/README.md b/www/lib/filelogger/README.md new file mode 100644 index 00000000..1d6c6456 --- /dev/null +++ b/www/lib/filelogger/README.md @@ -0,0 +1,123 @@ +Cordova File Logger +========== + +[](http://bower.io/search/?q=filelogger) + +Logger module for Cordova/Ionic projects. + +When you run your application in device the Logger writes in the local filesystem (with cordova-plugin-file) and the system logs (with console.log). + +When you run your application in browser with „ionic serve” the Logger uses browsers localStorage and the browser console (with console.log). + +## Dependencies + +- [ngCordova](http://ngcordova.com/) ( required version v0.1.14-alpha ) +- [org.apache.cordova.file](https://github.com/apache/cordova-plugin-file) + +## Installation + +Install manually, or from bower: + +```bash +$ bower install filelogger +``` + +Include *filelogger.min.js* and ng-cordova.js or *ng-cordova.min.js* in your index.html file before cordova.js and after your AngularJS / Ionic file (since ngCordova depends on AngularJS). + +```html +<script src="lib/ngCordova/dist/ng-cordova.min.js"></script> +<script src="lib/filelogger/dist/filelogger.min.js"></script> +<script src="cordova.js"></script> +``` + +Comment: you don't have to use the complete ngCordova package. I suggest to create a [Custom Build](http://ngcordova.com/build/) with file module. + + +## Usage + +### $fileLogger.log() + +General logger method. The first parameter is the log level (debug, info, warn, error). The following parameters are the message parts. +You can put here any javascript type (string, number, boolean, object, array). + +In the logfile every item starts with the current UTC timestamp, followed by the log level and the message. + +### $fileLogger.debug() + +Wrapper for $fileLogger.log('debug', ...) + +### $fileLogger.info() + +Wrapper for $fileLogger.log('info', ...) + +### $fileLogger.warn() + +Wrapper for $fileLogger.log('warn', ...) + +### $fileLogger.error() + +Wrapper for $fileLogger.log('error', ...) + +### $fileLogger.setStorageFilename() + +You can set the local filename (default messages.log). It requests one parameter, the filename (type string). + +### $fileLogger.getLogfile() + +You can read the whole logfile from the filestore. This method returns a promise. + +### $fileLogger.deleteLogfile() + +You can delete the logfile from the filestore. This method returns a promise. + + + +### Example use + +```js +angular.module('starter', ['ionic', 'fileLogger']) + .controller('mainCtrl', ['$scope', '$fileLogger', function($scope, $fileLogger) { + + function testing() { + + $fileLogger.setStorageFilename('myLog.txt'); + + $fileLogger.log('debug', 'message'); + $fileLogger.log('info', 'message'); + $fileLogger.log('warn', 'message'); + $fileLogger.log('error', 'message'); + + $fileLogger.debug('message'); + $fileLogger.info('message'); + $fileLogger.warn('message'); + $fileLogger.error('message'); + + $fileLogger.log('error', 'error message', { code: 1, meaning: 'general' }); + + $fileLogger.log('info', 'message', 123, [1, 2, 3], { a: 1, b: '2' }); + + $fileLogger.getLogfile().then(function(l) { + console.log('Logfile content'); + console.log(l); + }); + + $fileLogger.deleteLogfile().then(function() { + console.log('Logfile deleted'); + }); + + } + +}]); +``` + + +## Author + +#### Peter Bakondy + +- https://github.com/pbakondy + + +## LICENSE + +Cordova File Logger is licensed under the MIT Open Source license. For more information, see the LICENSE file in this repository. diff --git a/www/lib/filelogger/bower.json b/www/lib/filelogger/bower.json new file mode 100644 index 00000000..d6a109bd --- /dev/null +++ b/www/lib/filelogger/bower.json @@ -0,0 +1,30 @@ +{ + "name": "filelogger", + "version": "1.1.0", + "homepage": "https://github.com/pbakondy/filelogger", + "authors": [ + "Peter Bakondy <pbakondy@gmail.com>" + ], + "description": "Cordova library to log messages to local filesystem", + "main": "./dist/filelogger.min.js", + "ignore": [ + "**/.*", + "gulpfile.js", + "src", + "config" + ], + "dependencies": { + "ngCordova": ">= 0.1.14-alpha" + }, + "keywords": [ + "cordova", + "cordova plugin", + "ionic", + "ionic plugin", + "angular module", + "log", + "logger", + "file logger" + ], + "license": "MIT" +} diff --git a/www/lib/filelogger/dist/filelogger.js b/www/lib/filelogger/dist/filelogger.js new file mode 100644 index 00000000..c266f22a --- /dev/null +++ b/www/lib/filelogger/dist/filelogger.js @@ -0,0 +1,274 @@ +/*! + * fileLogger + * Copyright 2015 Peter Bakondy https://github.com/pbakondy + * See LICENSE in this repository for license information + */ +(function(){ +/* global angular, console, cordova */ + +// install : cordova plugin add org.apache.cordova.file + +angular.module('fileLogger', ['ngCordova.plugins.file']) + + .factory('$fileLogger', ['$q', '$window', '$cordovaFile', '$timeout', function ($q, $window, $cordovaFile, $timeout) { + 'use strict'; + + + var queue = []; + var ongoing = false; + var levels = ['DEBUG', 'INFO', 'WARN', 'ERROR']; + + var storageFilename = 'messages.log'; + + + function isBrowser() { + return (!$window.cordova && !$window.PhoneGap && !$window.phonegap); + } + + + function log(level) { + if (angular.isString(level)) { + level = level.toUpperCase(); + + if (levels.indexOf(level) === -1) { + level = 'INFO'; + } + } else { + level = 'INFO'; + } + + var timestamp = (new Date()).toJSON(); + + var messages = Array.prototype.slice.call(arguments, 1); + var message = [ timestamp, level ]; + + for (var i = 0; i < messages.length; i++ ) { + if (angular.isArray(messages[i])) { + message.push(JSON.stringify(messages[i])); + } + else if (angular.isObject(messages[i])) { + message.push(JSON.stringify(messages[i])); + } + else { + message.push(messages[i]); + } + } + + if (isBrowser()) { + // log to browser console + + messages.unshift(timestamp); + + if (angular.isObject(console) && angular.isFunction(console.log)) { + switch (level) { + case 'DEBUG': + if (angular.isFunction(console.debug)) { + console.debug.apply(console, messages); + } else { + console.log.apply(console, messages); + } + break; + case 'INFO': + if (angular.isFunction(console.debug)) { + console.info.apply(console, messages); + } else { + console.log.apply(console, messages); + } + break; + case 'WARN': + if (angular.isFunction(console.debug)) { + console.warn.apply(console, messages); + } else { + console.log.apply(console, messages); + } + break; + case 'ERROR': + if (angular.isFunction(console.debug)) { + console.error.apply(console, messages); + } else { + console.log.apply(console, messages); + } + break; + default: + console.log.apply(console, messages); + } + } + + } else { + // log to logcat + console.log(message.join(' ')); + } + + queue.push({ message: message.join(' ') + '\n' }); + + if (!ongoing) { + process(); + } + } + + + function process() { + + if (!queue.length) { + ongoing = false; + return; + } + + ongoing = true; + var m = queue.shift(); + + writeLog(m.message).then( + function() { + $timeout(function() { + process(); + }); + }, + function() { + $timeout(function() { + process(); + }); + } + ); + + } + + + function writeLog(message) { + var q = $q.defer(); + + if (isBrowser()) { + // running in browser with 'ionic serve' + + if (!$window.localStorage[storageFilename]) { + $window.localStorage[storageFilename] = ''; + } + + $window.localStorage[storageFilename] += message; + q.resolve(); + + } else { + + $cordovaFile.checkFile(cordova.file.dataDirectory, storageFilename).then( + function() { + // writeExistingFile(path, fileName, text) + $cordovaFile.writeExistingFile(cordova.file.dataDirectory, storageFilename, message).then( + function() { + q.resolve(); + }, + function(error) { + q.reject(error); + } + ); + }, + function() { + // writeFile(path, fileName, text, replaceBool) + $cordovaFile.writeFile(cordova.file.dataDirectory, storageFilename, message, true).then( + function() { + q.resolve(); + }, + function(error) { + q.reject(error); + } + ); + } + ); + + } + + return q.promise; + } + + + function getLogfile() { + var q = $q.defer(); + + if (isBrowser()) { + q.resolve($window.localStorage[storageFilename]); + } else { + $cordovaFile.readAsText(cordova.file.dataDirectory, storageFilename).then( + function(result) { + q.resolve(result); + }, + function(error) { + q.reject(error); + } + ); + } + + return q.promise; + } + + + function deleteLogfile() { + var q = $q.defer(); + + if (isBrowser()) { + $window.localStorage.removeItem(storageFilename); + q.resolve(); + } else { + $cordovaFile.removeFile(cordova.file.dataDirectory, storageFilename).then( + function(result) { + q.resolve(result); + }, + function(error) { + q.reject(error); + } + ); + } + + return q.promise; + } + + + function setStorageFilename(filename) { + if (angular.isString(filename) && filename.length > 0) { + storageFilename = filename; + return true; + } else { + return false; + } + } + + + function debug() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift('DEBUG'); + log.apply(undefined, args); + } + + + function info() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift('INFO'); + log.apply(undefined, args); + } + + + function warn() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift('WARN'); + log.apply(undefined, args); + } + + + function error() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift('ERROR'); + log.apply(undefined, args); + } + + + return { + log: log, + getLogfile: getLogfile, + deleteLogfile: deleteLogfile, + setStorageFilename: setStorageFilename, + debug: debug, + info: info, + warn: warn, + error: error + }; + + }]); + +})(); diff --git a/www/lib/filelogger/dist/filelogger.min.js b/www/lib/filelogger/dist/filelogger.min.js new file mode 100644 index 00000000..366521a2 --- /dev/null +++ b/www/lib/filelogger/dist/filelogger.min.js @@ -0,0 +1,6 @@ +/*! + * fileLogger + * Copyright 2015 Peter Bakondy https://github.com/pbakondy + * See LICENSE in this repository for license information + */ +!function(){angular.module("fileLogger",["ngCordova.plugins.file"]).factory("$fileLogger",["$q","$window","$cordovaFile","$timeout",function(e,o,n,r){"use strict";function l(){return!o.cordova&&!o.PhoneGap&&!o.phonegap}function t(e){angular.isString(e)?(e=e.toUpperCase(),-1===h.indexOf(e)&&(e="INFO")):e="INFO";for(var o=(new Date).toJSON(),n=Array.prototype.slice.call(arguments,1),r=[o,e],t=0;t<n.length;t++)r.push(angular.isArray(n[t])?JSON.stringify(n[t]):angular.isObject(n[t])?JSON.stringify(n[t]):n[t]);if(l()){if(n.unshift(o),angular.isObject(console)&&angular.isFunction(console.log))switch(e){case"DEBUG":angular.isFunction(console.debug)?console.debug.apply(console,n):console.log.apply(console,n);break;case"INFO":angular.isFunction(console.debug)?console.info.apply(console,n):console.log.apply(console,n);break;case"WARN":angular.isFunction(console.debug)?console.warn.apply(console,n):console.log.apply(console,n);break;case"ERROR":angular.isFunction(console.debug)?console.error.apply(console,n):console.log.apply(console,n);break;default:console.log.apply(console,n)}}else console.log(r.join(" "));v.push({message:r.join(" ")+"\n"}),y||a()}function a(){if(!v.length)return void(y=!1);y=!0;var e=v.shift();i(e.message).then(function(){r(function(){a()})},function(){r(function(){a()})})}function i(r){var t=e.defer();return l()?(o.localStorage[m]||(o.localStorage[m]=""),o.localStorage[m]+=r,t.resolve()):n.checkFile(cordova.file.dataDirectory,m).then(function(){n.writeExistingFile(cordova.file.dataDirectory,m,r).then(function(){t.resolve()},function(e){t.reject(e)})},function(){n.writeFile(cordova.file.dataDirectory,m,r,!0).then(function(){t.resolve()},function(e){t.reject(e)})}),t.promise}function c(){var r=e.defer();return l()?r.resolve(o.localStorage[m]):n.readAsText(cordova.file.dataDirectory,m).then(function(e){r.resolve(e)},function(e){r.reject(e)}),r.promise}function s(){var r=e.defer();return l()?(o.localStorage.removeItem(m),r.resolve()):n.removeFile(cordova.file.dataDirectory,m).then(function(e){r.resolve(e)},function(e){r.reject(e)}),r.promise}function u(e){return angular.isString(e)&&e.length>0?(m=e,!0):!1}function g(){var e=Array.prototype.slice.call(arguments,0);e.unshift("DEBUG"),t.apply(void 0,e)}function f(){var e=Array.prototype.slice.call(arguments,0);e.unshift("INFO"),t.apply(void 0,e)}function p(){var e=Array.prototype.slice.call(arguments,0);e.unshift("WARN"),t.apply(void 0,e)}function d(){var e=Array.prototype.slice.call(arguments,0);e.unshift("ERROR"),t.apply(void 0,e)}var v=[],y=!1,h=["DEBUG","INFO","WARN","ERROR"],m="messages.log";return{log:t,getLogfile:c,deleteLogfile:s,setStorageFilename:u,debug:g,info:f,warn:p,error:d}}])}(); diff --git a/www/lib/filelogger/package.json b/www/lib/filelogger/package.json new file mode 100644 index 00000000..0f1619a0 --- /dev/null +++ b/www/lib/filelogger/package.json @@ -0,0 +1,26 @@ +{ + "name": "filelogger", + "private": false, + "main": "dist/filelogger", + "version": "1.1.0", + "repository": { + "url": "git://github.com/pbakondy/filelogger.git" + }, + "devDependencies": { + "gulp": "^3.7.0", + "gulp-footer": "^1.0.4", + "gulp-header": "^1.0.2", + "gulp-jshint": "^1.6.1", + "gulp-rename": "^1.2.0", + "gulp-uglify": "^0.2.1", + "jshint-stylish": "^0.4.0", + "minimist": "^0.1.0" + }, + "licenses": [ + { + "type": "MIT" + } + ], + "dependencies": { + } +} diff --git a/www/templates/log.html b/www/templates/log.html new file mode 100644 index 00000000..102877ae --- /dev/null +++ b/www/templates/log.html @@ -0,0 +1,16 @@ +<ion-view view-title="Logs"> + + <ion-nav-buttons side="left"> + <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> + </ion-nav-buttons> + + <ion-nav-buttons side="right"> + <a style="" class="button button-icon icon ion-email" ng-href="" ng-click="sendEmail(zmLog.logString)" > </a> + </ion-nav-buttons> + + <ion-content class="padding"> + <pre> + {{zmLog.logString}} + </pre> + + </ion-content> |
