|
|
/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0
* * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */
//------------------------------------------------------------------------------
// The logger module exports the following properties/functions:
//
// LOG - constant for the level LOG
// ERROR - constant for the level ERROR
// WARN - constant for the level WARN
// INFO - constant for the level INFO
// DEBUG - constant for the level DEBUG
// logLevel() - returns current log level
// logLevel(value) - sets and returns a new log level
// useConsole() - returns whether logger is using console
// useConsole(value) - sets and returns whether logger is using console
// log(message,...) - logs a message at level LOG
// error(message,...) - logs a message at level ERROR
// warn(message,...) - logs a message at level WARN
// info(message,...) - logs a message at level INFO
// debug(message,...) - logs a message at level DEBUG
// logLevel(level,message,...) - logs a message specified level
//
//------------------------------------------------------------------------------
var logger = exports;
var exec = require('cordova/exec');
var UseConsole = false; var UseLogger = true; var Queued = []; var DeviceReady = false; var CurrentLevel;
var originalConsole = console;
/** * Logging levels */
var Levels = [ "LOG", "ERROR", "WARN", "INFO", "DEBUG" ];
/* * add the logging levels to the logger object and * to a separate levelsMap object for testing */
var LevelsMap = {}; for (var i=0; i<Levels.length; i++) { var level = Levels[i]; LevelsMap[level] = i; logger[level] = level; }
CurrentLevel = LevelsMap.WARN;
/** * Getter/Setter for the logging level * * Returns the current logging level. * * When a value is passed, sets the logging level to that value. * The values should be one of the following constants: * logger.LOG * logger.ERROR * logger.WARN * logger.INFO * logger.DEBUG * * The value used determines which messages get printed. The logging * values above are in order, and only messages logged at the logging * level or above will actually be displayed to the user. E.g., the * default level is WARN, so only messages logged with LOG, ERROR, or * WARN will be displayed; INFO and DEBUG messages will be ignored. */ logger.level = function (value) { if (arguments.length) { if (LevelsMap[value] === null) { throw new Error("invalid logging level: " + value); } CurrentLevel = LevelsMap[value]; }
return Levels[CurrentLevel]; };
/** * Getter/Setter for the useConsole functionality * * When useConsole is true, the logger will log via the * browser 'console' object. */ logger.useConsole = function (value) { if (arguments.length) UseConsole = !!value;
if (UseConsole) { if (typeof console == "undefined") { throw new Error("global console object is not defined"); }
if (typeof console.log != "function") { throw new Error("global console object does not have a log function"); }
if (typeof console.useLogger == "function") { if (console.useLogger()) { throw new Error("console and logger are too intertwingly"); } } }
return UseConsole; };
/** * Getter/Setter for the useLogger functionality * * When useLogger is true, the logger will log via the * native Logger plugin. */ logger.useLogger = function (value) { // Enforce boolean
if (arguments.length) UseLogger = !!value; return UseLogger; };
/** * Logs a message at the LOG level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.log = function(message) { logWithArgs("LOG", arguments); };
/** * Logs a message at the ERROR level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.error = function(message) { logWithArgs("ERROR", arguments); };
/** * Logs a message at the WARN level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.warn = function(message) { logWithArgs("WARN", arguments); };
/** * Logs a message at the INFO level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.info = function(message) { logWithArgs("INFO", arguments); };
/** * Logs a message at the DEBUG level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.debug = function(message) { logWithArgs("DEBUG", arguments); };
// log at the specified level with args
function logWithArgs(level, args) { args = [level].concat([].slice.call(args)); logger.logLevel.apply(logger, args); }
// return the correct formatString for an object
function formatStringForMessage(message) { return (typeof message === "string") ? "" : "%o"; }
/** * Logs a message at the specified level. * * Parameters passed after message are used applied to * the message with utils.format() */ logger.logLevel = function(level /* , ... */) { // format the message with the parameters
var formatArgs = [].slice.call(arguments, 1); var fmtString = formatStringForMessage(formatArgs[0]); if (fmtString.length > 0){ formatArgs.unshift(fmtString); // add formatString
}
var message = logger.format.apply(logger.format, formatArgs);
if (LevelsMap[level] === null) { throw new Error("invalid logging level: " + level); }
if (LevelsMap[level] > CurrentLevel) return;
// queue the message if not yet at deviceready
if (!DeviceReady && !UseConsole) { Queued.push([level, message]); return; }
// Log using the native logger if that is enabled
if (UseLogger) { exec(null, null, "Console", "logLevel", [level, message]); }
// Log using the console if that is enabled
if (UseConsole) { // make sure console is not using logger
if (console.useLogger()) { throw new Error("console and logger are too intertwingly"); }
// log to the console
switch (level) { case logger.LOG: originalConsole.log(message); break; case logger.ERROR: originalConsole.log("ERROR: " + message); break; case logger.WARN: originalConsole.log("WARN: " + message); break; case logger.INFO: originalConsole.log("INFO: " + message); break; case logger.DEBUG: originalConsole.log("DEBUG: " + message); break; } } };
/** * Formats a string and arguments following it ala console.log() * * Any remaining arguments will be appended to the formatted string. * * for rationale, see FireBug's Console API: * http://getfirebug.com/wiki/index.php/Console_API
*/ logger.format = function(formatString, args) { return __format(arguments[0], [].slice.call(arguments,1)).join(' '); };
//------------------------------------------------------------------------------
/** * Formats a string and arguments following it ala vsprintf() * * format chars: * %j - format arg as JSON * %o - format arg as JSON * %c - format arg as '' * %% - replace with '%' * any other char following % will format it's * arg via toString(). * * Returns an array containing the formatted string and any remaining * arguments. */ function __format(formatString, args) { if (formatString === null || formatString === undefined) return [""]; if (arguments.length == 1) return [formatString.toString()];
if (typeof formatString != "string") formatString = formatString.toString();
var pattern = /(.*?)%(.)(.*)/; var rest = formatString; var result = [];
while (args.length) { var match = pattern.exec(rest); if (!match) break;
var arg = args.shift(); rest = match[3]; result.push(match[1]);
if (match[2] == '%') { result.push('%'); args.unshift(arg); continue; }
result.push(__formatted(arg, match[2])); }
result.push(rest);
var remainingArgs = [].slice.call(args); remainingArgs.unshift(result.join('')); return remainingArgs; }
function __formatted(object, formatChar) {
try { switch(formatChar) { case 'j': case 'o': return JSON.stringify(object); case 'c': return ''; } } catch (e) { return "error JSON.stringify()ing argument: " + e; }
if ((object === null) || (object === undefined)) { return Object.prototype.toString.call(object); }
return object.toString(); }
//------------------------------------------------------------------------------
// when deviceready fires, log queued messages
logger.__onDeviceReady = function() { if (DeviceReady) return;
DeviceReady = true;
for (var i=0; i<Queued.length; i++) { var messageArgs = Queued[i]; logger.logLevel(messageArgs[0], messageArgs[1]); }
Queued = null; };
// add a deviceready event to log queued messages
document.addEventListener("deviceready", logger.__onDeviceReady, false);
|