/** * Send log messages to the console, filtered by log level. * * The log levels available are properties on this object: * * Ext.space.Logger.LOG // "LOG" * Ext.space.Logger.ERROR // "ERROR" * Ext.space.Logger.WARN // "WARN" * Ext.space.Logger.INFO // "INFO" (default) * Ext.space.Logger.DEBUG // "DEBUG" * * Each log level has a corresponding method that logs its arguments to the console * using the appropriate method on the console, optionally prefixed by the name of * the log level. Messages logged with `Ext.space.Logger.log(...)` are always logged * regardless of the current log level, but the rest take it into account. * * var logger = Ext.space.Logger; * * logger.level(); // "INFO" by default * * logger.log("This message is always logged no matter what"); * logger.info("Info level message, gets skipped."); * * logger.level(logger.DEBUG); * * logger.info("Info level message, gets shown this time."); * * logger.usePrefix = true; * logger.warn("This one will be prefixed by 'WARN'"); * * logger.error("Multiple", ["argument", "error"], {prop: "message"}); * * Note that the "ERROR" log level doesn't throw actual errors; that's up to the * application itself. * * You can also track custom application-defined events (defined as a collection of * basically arbitrary strings: category, action, label (optional), extra (optional)) * with Ext.space.Logger.logEvent(). These get logged at the level provided to * Ext.space.Logger.eventLevel(...) (default Ext.space.Logger.INFO), and also * submitted to the Sencha Web Application Manager server for report generation in * the administration console. * */Ext.define('Ext.space.Logger', { singleton: true, /** * @readonly */ LOG: "LOG", /** * @readonly */ ERROR: "ERROR", /** * @readonly */ WARN: "WARN", /** * @readonly */ INFO: "INFO", /** * @readonly */ DEBUG: "DEBUG", /** * @private */ levels: null, /** * @private */ _level: 0, /** * @private */ _eventLevel: 0, /** * Determines whether logged messages are prefixed with their log level. * type {Boolean} */ usePrefix: false, /** * @private */ constructor: function() { this.levels = { byLevel: [this.ERROR, this.WARN, this.INFO, this.DEBUG], byName: {} }; var idx = this.levels.byName; var name = this.levels.byLevel; for (var i=0; i<name.length; i++) { idx[name[i]] = i; if (name[i] != this.LOG) { var method = this._getLevelMethodName(name[i]); this[method] = this._mklogger(method, name[i], i); } } this.level(this.INFO); this.eventLevel(this.INFO); }, /** * Creates the logging methods * @private */ _mklogger: function(method, prefix, level) { return function() { if (level <= this._level) { console[method].apply(console, this.usePrefix ? [prefix].concat(Array.prototype.slice.call(arguments)) : arguments); } }; }, /** * Convert a level name to a method name * @private */ _getLevelMethodName: function(levelName) { return levelName.toLowerCase(); }, /** * Log a message to the console, regardless of the log level. */ log: function() { console.log.apply(console, this.usePrefix ? [this.LOG].concat(Array.prototype.slice.call(arguments)) : arguments); }, /** * Get or set the current log level for the given internal property name. * @private */ _doLevel: function(prop, levelName) { if (arguments.length) { // only change the level if it's directly supported; otherwise no-op if (this.levels.byName.hasOwnProperty(levelName)) { this[prop] = this.levels.byName[levelName]; } } return this.levels.byLevel[this[prop]]; }, /** * Get or set the current log level. * * @param {String} levelName (optional) log level to set: "ERROR", "WARN", "INFO", "DEBUG" * @return {String} Current log level */ level: function(levelName) { return this._doLevel("_level", levelName); }, /** * Get or set the current log level to be used for custom events. * * @param {String} levelName (optional) log level to set: "ERROR", "WARN", "INFO", "DEBUG" * @return {String} Current log level */ eventLevel: function(levelName) { return this._doLevel("_eventLevel", levelName); }, /** * Send a custom event to the server. * * Events are a somewhat free-form set of arbitrary strings that facilitate * grouping in administrative reports. They're required to have a `category` and * `action` and can optionally also be given a `label` and/or `extra` data. Sencha * Web Application Client will attempt to submit the event data to the server, * and if the server is not accessible (for example, if the user is offline), it * will store the event for submission later. * * Ext.space.Logger.logEvent({ * category: "Contact", * action: "Contact form submission", * label: "From footer", * extra: "[email protected]" * }).then(function() { * // do something, if you want * }, function(error) { * // something went wrong, nothing worked, everything is terrible * }); * * @param {Object} kwArgs Custom event definition * @param {String} kwArgs.category Event category name * @param {String} kwArgs.action Event action name * @param {String} kwArgs.label (optional) Event label * @param {String} kwArgs.extra (optional) Extra event information * @return {Ext.space.Promise} Promise that resolves when the event is sent */ logEvent: function(kwArgs) { var result = new Ext.space.Promise(); if (kwArgs) { if (!kwArgs.category) { result.reject("Missing required event category"); } else if (!kwArgs.action) { result.reject("Missing required event action"); } else { var args = { command: "Event#log", timestamp: Date.now(), category: kwArgs.category, action: kwArgs.action, callbacks: { onSuccess: function() { result.fulfill(); }, onError: function(error) { result.reject(error); } } }; if (kwArgs.label) { args.label = kwArgs.label; } if (kwArgs.extra) { args.extra = kwArgs.extra; } // so... much... indirection... this[this._getLevelMethodName(this.eventLevel())]("Event:", kwArgs); Ext.space.Communicator.send(args); } } else { result.reject("Missing event descriptor"); } return result; }});