Source: tools/logger.js

/*
 * 	Copyright (C) 2012-2015 DFKI GmbH
 * 	Deutsches Forschungszentrum fuer Kuenstliche Intelligenz
 * 	German Research Center for Artificial Intelligence
 * 	http://www.dfki.de
 * 
 * 	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.
 */



define(['mmirf/dictionary', 'mmirf/stacktrace', 'module'], 
/**
 * A Logger factory.<br>
 * 
 * @example 
 *  //use logger
 *  var Logger = mmir.require('mmirf/logger');
 *  var log = Logger.create('example');
 *  
 *  if(log.isVerbose()) log.debug('test');//will write the message to debug-console)
 *  log.error(new Error());//will write the error (including its stack) to error console)
 *  
 *  //example for setting up a logger in a requirejs-module:
 *  define(['mmirf/logger', 'module'], function(Logger, module){
 *  
 *    var logger = Logger.create(module);
 *    //this would create the same logger-object:
 *    //  Logger.create(module.id, module.config().logLevel);
 *    
 *    //use the logger instance...
 *    
 *    //create / retrieve the same logger
 *    var sameLogger = Logger.create(module.id);
 *    
 *  });
 *  
 * @class
 * @name Logging
 * @memberOf mmir
 * @static
 * 
 * @see Logger
 * 
 */	
function(Dictionary, stacktrace, module){

	
var _loggers = new Dictionary();
//var logLevels = new Dictionary();

/**
 * the (global) logging level
 * 
 * 0: verbose
 * 1: debug
 * 2: info
 * 3: warn
 * 4: error
 * 5: critical
 * 6: disabled
 * 
 * @memberOf mmir.Logging#
 */
var _level = 1;

/**
 * @private
 * @type String
 * @memberOf mmir.Logging#
 */
var tmpLogLevel = module.config().logLevel;
if(typeof tmpLogLevel !== 'undefined'){
	if(typeof tmpLogLevel !== 'number'){
		tmpLogLevel = getAsLevel(tmpLogLevel);
	}
	_level = tmpLogLevel;
}


//	//TODO extend / implement helpers for writing CSV file data
//	var csvHeader = [
//	    'User name', 'Time', 'Modality', 'Recognized speech', 'Event name', 'Event data', 'Dialog state'
//	];
//	
//	function getCsvLine(){
//		return new Array(csvHeader.length);
//	}

/**
 * Get the log-level as number.
 * 
 * @param {String} strLogLevel
 * 			the string representation for the log-level
 * @returns {Number}
 * 				the log-level as number
 * @private
 * @memberOf Logger.prototype
 * 
 * @see #getLevel
 */
function getAsLevel(strLogLevel){
	if(typeof strLogLevel === 'string'){
		var str = strLogLevel.toLowerCase();
		if(str === 'verbose'){
			return 0;
		} else if(str === 'debug'){
			return 1;
		} else if(str === 'info'){
			return 2;
		} else if(str === 'warn'){
			return 3;
		} else if(str === 'error'){
			return 4;
		} else if(str === 'critical'){
			return 5;
		} else if(str === 'disabled'){
			return 6;
		} else
			throw new Error('Logger.getAsLevel: unknown parameter value "'+strLogLevel+'"');
	}
	
	throw new TypeError('Logger.getAsLevel: parameter must be number or string, but "'+strLogLevel+'" is '+typeof strLogLevel);
}

/**
 * print log message with error information.
 * 
 * @private
 * @memberOf Logger.prototype
 */
function printe(loggerName, logLevel, className, funcName, msg, error){
	
	if( isErr(className)){
		error = className;
		className = '';
	} else if( isErr(funcName) ){
		error = funcName;
		funcName = void(0);
		if(typeof className === 'undefined'){
			className = '';
		}
	} else if( isErr(msg) ){
		error = msg;
		msg = void(0);
		if(typeof className === 'undefined'){
			if(typeof funcName === 'undefined'){
				className = '';
			}
			else {
				className = funcName;
				funcName = void(0);
			}
		}
	}
	
	print(loggerName, logLevel, createErr(createMsg(className, funcName, msg), error), true);
}

/**
 * creates the message text.
 * 
 * @returns {string} the message text
 * 
 * @private
 * @memberOf Logger.prototype
 */
function createMsg(className, funcName, msg){
	
	var out;
	
	if(className){
		if(funcName){
			if(msg){
				out = className+'.'+funcName+': '+msg;
			} else {
				
//					if(arguments.callee !== 'undefined'){
//						out('callee: '+arguments.callee());
//					}
				
				out = className+': '+funcName;
			}
		} else {
			
//				if(arguments.callee !== 'undefined'){
//					out('callee: '+arguments.callee());
//				}
			
			out = className;
		}
	} else {

//			if(arguments.callee !== 'undefined'){
//				out('callee: '+arguments.callee());
//			}
		
		if(typeof className === 'undefined'){
			out = 'UNDEFINED';
		} else if(typeof className !== 'string'){
			out = Object.prototype.toString.call(null, className);
		} else {
			out = className;
		}
	}
	
	return out;
}

/**
 * HELPER: check if errObj is an Error
 * 
 * @returns {Boolean}
 * 
 * @private
 * @memberOf Logger.prototype
 */
function isErr(errObj){
	
	//TODO also do feature detection for error-like objects?
	return errObj instanceof Error;
}

/**
 * Creates error message (with stack trace, if possible).
 * 
 * @returns {string} the error message
 * 
 * @private
 * @memberOf Logger.prototype
 */
function createErr(msg, error){
	
	var err ='';
	var errMsg = '';
	var re;
	if(error){
		
		if(error.name){
			err = '<'+error.name+'> ';
		}
		
		if(error.number){
			err += '#'+error.number+' ';
		}
		
		if(error.stack){
			
			errMsg = error.stack;
			
			if(error.name && (re = new RegExp('^'+error.name)).test(errMsg)){
				errMsg = errMsg.replace(re, '');
			}
			
		} else {

			if(error.message){
				errMsg = ' - ' + error.message;
			}
			
			if(error.description){
				errMsg = ' - ' + error.description;
			}
			
			if(error.fileName){
				
				var lineNo = '';
				
				if(error.lineNumber){
					lineNo = ', line ' + error.lineNumber;
				}
				
				errorMsg += ' ('+error.fileName+lineNo+')'; 
			}
		}
		
	}
	
	return err+msg+errMsg;
}

//in some environments console.debug may not exits -> use console.log instead
var DEBUG_FUNC_NAME = console.debug? 'debug' : 'log';

/**
 * @private
 * @memberOf Logger.prototype
 */
function print(loggerName, logLevel, msg){
	var prefix, func;
	switch(logLevel){
	case 0:
		prefix = '[VERBOSE] ';
		func = 'log';
		break;
	case 1:
		prefix = '[DEBUG] ';
		func = DEBUG_FUNC_NAME;
		break;
	case 2:
		prefix = '[INFO] ';
		func = 'info';
		break;
	case 3:
		prefix = '[WARN] ';
		func = 'warn';
		break;
	case 4:
		prefix = '[ERROR] ';
		func = 'error';
		break;
	case 5:
		prefix = '[CRITICAL] ';
		func = 'error';
		break;
	case 6:		//debug-level "disabled" -> do nothing
		return; /////////////////// EARLY EXIT //////////
	default:
		prefix = '[UNDEF_LOG_LEVEL_'+logLevel+'] ';
		func = 'log';
		break;
	}
	console[func](prefix + loggerName + msg);
}


//enable tracing?
/**
 * configuration value for enabling/disabling tracing in log-output
 * @private
 * @type Object
 * @memberOf Logger.prototype
 */
var tmpTraceConfig = module.config().trace;
if(tmpTraceConfig !== false || (tmpTraceConfig !== null && typeof tmpTraceConfig === 'object' && tmpTraceConfig.trace === true)){

	/**
	 * options object for tracing
	 * @private
	 * @type Object
	 * @memberOf Logger.prototype
	 */
	var pnTraceOptions = tmpTraceConfig === true? void(0) : tmpTraceConfig;
	/**
	 * setting for trace-depth (i.e. stack-depth)
	 * @private
	 * @type Boolean
	 * @memberOf Logger.prototype
	 */
	var isFullStackDepth = pnTraceOptions && pnTraceOptions.depth === "full";
	
	/**
	 * proxy object for storing the original implementation
	 * of {@link Logger.prototype#print} function.
	 * 
	 * (only used, if tracing is enabled!)
	 * 
	 * @private
	 * @type Function
	 * @memberOf Logger.prototype
	 */
	var pnOriginal = print;
	
	//do enable tracing: append stacktrace to messages in print-function
	if(isFullStackDepth){
		
		//NOTE code duplication for the sake of a more efficient print function
		
		/**
		 * Extension for {@link Logger.prototype#print} function with tracing.
		 * 
		 * This extension prints the full stack trace in log-output.
		 * 
		 * (only used, if tracing is enabled!)
		 * 
		 * @private
		 * @name printFullStack
		 * @function
		 * @memberOf Logger.prototype
		 */
		print = function printFullStack(loggerName, logLevel, msg, isErrInvoked){
			if(typeof msg === 'undefined' || msg === null){
				msg = '';
			}
			//if isErrInvoked is TRUE: this function was invoked via additional printe()-call
			// => need to take 1 more step down the stack
			msg += '\n  ' + stacktrace(pnTraceOptions).slice(isErrInvoked? 6 : 5).join('\n  ');
			pnOriginal.call(this, loggerName, logLevel, msg);
		};
	}
	else {
		
		//NOTE code duplication for the sake of a more efficient print function
		
		/**
		 * Extension for {@link Logger.prototype#print} function with tracing.
		 * 
		 * This extension prints only the first entry of the stack trace in log-output.
		 * 
		 * (only used, if tracing is enabled!)
		 * 
		 * @private
		 * @name printStack
		 * @function
		 * @memberOf Logger.prototype
		 */
		print = function printStack(loggerName, logLevel, msg, isErrInvoked){
			if(typeof msg === 'undefined' || msg === null){
				msg = '';
			}
			//if isErrInvoked is TRUE: this function was invoked via additional printe()-call
			// => need to take 1 more step down the stack
			msg += '\n  ' + stacktrace(pnTraceOptions)[isErrInvoked? 6 : 5];
			pnOriginal.call(this, loggerName, logLevel, msg);
		};
	}

}

/**
 * Constructor-Method of Class Logger<br>
 * @constructor
 * @class Logger
 * @name Logger
 * 
 * @param {String} theName
 * 					the name / ID for the logger
 * @param {String|Number} [theLevel] OPTIONAL
 * 					the log-level.
 * 					If omitted, the logger will use
 * 					the default log-level
 *  
 * @see #getAsLevel
 * @see #getLevel
 */
function Logger(theName, theLevel){
	
	//the name (/key) for the logger instance
	this.name = '';
	if(typeof theName !== 'undefined'){
		this.name = '['+theName+'] ';
	}
	
	if(typeof theLevel !== 'undefined'){
		if(typeof theLevel !== 'number'){
			theLevel = getAsLevel(theLevel);
		}
		
		this.level = theLevel;
	}
}

Logger.prototype =
/** @lends Logger# */
{//public instance members
	
	/**
	 * Get the current log-level:
	 * if a specific log-level for this Logger instance is set,
	 * this value is returned.
	 * Otherwise, the default log-level as returned by {@link mmir.Logging#getDefaultLogLevel}
	 * is used.
	 * 
	 * Log-levels:
	 * <ul>
	 * 	<li>0: verbose</li>
	 * 	<li>1: debug</li>
	 * 	<li>2: info</li>
	 * 	<li>3: warn</li>
	 * 	<li>4: error</li>
	 * 	<li>5: critical</li>
	 * 	<li>6: disabled</li>
	 * <ul>
	 * 
	 * @returns {Number} the logging level
	 * 
	 * @see #setLevel
	 */
    getLevel : function(){
    	
    	if(typeof this.level !== 'undefined'){
    		return this.level;
    	}
    	
    	//return default/global logging-level:
    	return _level;
    },
    /**
     * Set the logging level.
     * 
     * @param {String|Number} loggingLevel
     * 						if {Number} the logging level as a number
     *                      if {String} the logging level as a string (see {@link #getLevel})
     *                      
	 * @see #getLevel
     */
    setLevel : function(loggingLevel){
    	
    	if(typeof loggingLevel !== 'number'){
    		loggingLevel = getAsLevel(loggingLevel);
    	}
    	
    	this.level = loggingLevel;
    },
    /**
     * 
     * Print a log message, if at least <code>debug</code> log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
     * @param {Error} [error] OPTIONAL
     * 			an error object: if available, its message and error-stack will be print to the output
	 * @public
	 */
    log: function(className, funcName, msg, error){
    	if(this.isDebug()){
    		printe(this.name, 1 /*getAsLevel('debug')*/, className, funcName, msg, error);
    	}
    },

    /**
     * 
     * Print a <em>verbose</em> log message, if at least <code>verbose</code> (0) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
	 * @public
	 */
    //TODO implement/add helpers for file-logging (+ CSV data helpers etc)
    verbose : function(className, funcName, msg){
    	if(this.isVerbose()){
    		print( this.name, 0 /*getAsLevel('verbose')*/, createMsg(className, funcName, msg));
    	}
    },

    /**
     * 
     * Print a <em>debug</em> log message, if at least <code>debug</code> (1) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
	 * @public
	 */
    debug : function(className, funcName, msg){
    	if(this.isDebug()){
    		print( this.name, 1 /*getAsLevel('debug')*/, createMsg(className, funcName, msg));
    	}
    },

    /**
     * 
     * Print an <em>information</em> log message, if at least <code>info</code> (2) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
	 * @public
	 */
    info : function(className, funcName, msg){
    	if(this.isInfo()){
    		print( this.name, 2 /*getAsLevel('info')*/, createMsg(className, funcName, msg));
    	}
    },

    /**
     * 
     * Print a <em>warning</em> log message, if at least <code>warn</code> (3) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
	 * @public
	 */
    warn : function(className, funcName, msg){
    	if(this.isWarn()){
    		print( this.name, 3 /*getAsLevel('warn')*/, createMsg(className, funcName, msg));
    	}
    },

    /**
     * 
     * Print an <em>error</em> log message, if at least <code>error</code> (4) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
     * @param {Error} [error] OPTIONAL
     * 			an error object: if available, its message and error-stack will be print to the output
	 * @public
	 */
    error : function(className, funcName, msg, error){
    	if(this.isError()){
    		printe(this.name, 4 /*getAsLevel('error')*/, className, funcName, msg, error);
    	}
    },

    /**
     * 
     * Print a <em>critical</em> (exception) log message, if at least <code>critical</code> (5) log-level is set.
     * 
     * @param {String} [className] OPTIONAL
     * 			the name of the class/object from which the logging is invoked from
     * @param {String} [funcName] OPTIONAL
     * 			the name of the function (within the class) from which the logging is invoked from
     * @param {String} msg
     * 			the log message
     * @param {Error} [error] OPTIONAL
     * 			an error object: if available, its message and error-stack will be print to the output
	 * @public
	 */
    critical : function(className, funcName, msg, error){
    	if(this.isCritical()){
    		printe(this.name, 5 /*getAsLevel('critical')*/, className, funcName, msg, error);
    	}
    },

    /**
     * 
     * Check if the current log-level is at least <code>verbose</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>verbose</code> (0) 
	 * @public
	 * 
	 * @see #verbose
	 */
    isVerbose : function(loggerName){
    	return this.getLevel() <= 0;// getAsLevel('verbose');
    },

    /**
     * 
     * Check if the current log-level is at least <code>debug</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>debug</code> (1) 
	 * @public
	 * 
	 * @see #debug
	 */
    isDebug : function(loggerName){
    	return this.getLevel() <= 1;//getAsLevel('debug');
    },

    /**
     * 
     * Check if the current log-level is at least <code>info</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>info</code> (2) 
	 * @public
	 * 
	 * @see #info
	 */
    isInfo : function(loggerName){
    	return this.getLevel() <= 2;//getAsLevel('info');
    },

    /**
     * 
     * Check if the current log-level is at least <code>warn</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>warn</code> (3) 
	 * @public
	 * 
	 * @see #warn
	 */
    isWarn : function(loggerName){
    	return this.getLevel() <= 3;//getAsLevel('warn');
    },

    /**
     * 
     * Check if the current log-level is at least <code>error</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>error</code> (4) 
	 * @public
	 * 
	 * @see #error
	 */
    isError : function(loggerName){
    	return this.getLevel() <= 4;//getAsLevel('error');
    },

    /**
     * 
     * Check if the current log-level is at least <code>critical</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>critical</code> (5) 
	 * @public
	 * 
	 * @see #critical
	 */
    isCritical : function(loggerName){
    	return this.getLevel() <= 5;//getAsLevel('critical');
    },

    /**
     * 
     * Check if the current log-level is at least <code>disabled</code>.
     * 
     * @returns {Boolean}
     * 				<code>true</code> if at least log-level <code>disable</code> (6) 
	 * @public
	 * 
	 * @see #getLevel
	 */
    isDisabled : function(loggerName){
    	return this.getLevel() <= 6;//getAsLevel('disabled');
    }
};

//define alias'

/**
 * Alias for {@link #log}.
 * 
 * @public
 * @var {Function} Logger#l
 */
Logger.prototype.l = function(){
	return this.log.apply(this, arguments);
};

/**
 * Alias for {@link #verbose}.
 * 
 * @public
 * @var {Function} Logger#v
 */
Logger.prototype.v = function(){
	return this.verbose.apply(this, arguments);
};

/**
 * Alias for {@link #debug}.
 * 
 * @public
 * @var {Function} Logger#d
 */
Logger.prototype.d = function(){
	return this.debug.apply(this, arguments);
};

/**
 * Alias for {@link #info}.
 * 
 * @public
 * @var {Function} Logger#i
 */
Logger.prototype.i = function(){
	return this.info.apply(this, arguments);
};

/**
 * Alias for {@link #warn}.
 * 
 * @public
 * @var {Function} Logger#w
 */
Logger.prototype.w = function(){
	return this.warn.apply(this, arguments);
};

/**
 * Alias for {@link #error}.
 * 
 * @public
 * @var {Function} Logger#e
 */
Logger.prototype.e = function(){
	return this.error.apply(this, arguments);
};

/**
 * Alias for {@link #critical}.
 * 
 * @public
 * @var {Function} Logger#c
 */
Logger.prototype.c = function(){
	return this.critical.apply(this, arguments);
};

/**
 * @scope Logger#
 */

/**
 * Alias for {@link #isVerbose}.
 * 
 * @public
 * @var {Function} Logger#isv
 */
Logger.prototype.isv = function(){
	return this.isVerbose.apply(this, arguments);
};

/**
 * Alias for {@link #isDebug}.
 * 
 * @public
 * @var {Function} Logger#isd
 */
Logger.prototype.isd = function(){
	return this.isDebug.apply(this, arguments);
};

/**
 * Alias for {@link #isInfo}.
 * 
 * @public
 * @var {Function} Logger#isi
 */
Logger.prototype.isi = function(){
	return this.isInfo.apply(this, arguments);
};

/**
 * Alias for {@link #isWarn}.
 * 
 * @public
 * @var {Function} Logger#isw
 */
Logger.prototype.isw = function(){
	return this.isWarn.apply(this, arguments);
};

/**
 * Alias for {@link #isError}.
 * 
 * @public
 * @var {Function} Logger#ise
 */
Logger.prototype.ise = function(){
	return this.isError.apply(this, arguments);
};

/**
 * Alias for {@link #isCritical}.
 * 
 * @public
 * @var {Function} Logger#isc
 */
Logger.prototype.isc = function(){
	return this.isCrictial.apply(this, arguments);
};


/**
 * @private
 * @type Logger
 * @memberOf mmir.Logging#
 */
var _defaultLogger = new Logger();
//default logger always has default/global log-level:
/**
 * @inheritdoc
 */
_defaultLogger.getLevel = function(){
	return _level;
};

//the instance for the Logging factory:
var instance =
/** @lends mmir.Logging.prototype */
{//public API
		
	/**
	 * Creates a {@link Logger} instance.
	 * 
	 * If a logger for <code>loggerName</code> already exists,
	 * the existing logger is returned (instead of creating a new one).
	 * 
	 * @param {String|Object} [loggerName]
	 * 			If String: a name / ID for the logger that should be created / retrieved.<br>
	 * 			If Object: an requirejs <code>module</code> object, i.e. should contain properties
	 * 							<code>id</code> (String) which will set the <code>loggerName</code>, and a property/function 
	 * 							<code>config</code> (Function) that returns an object with property
	 * 							<code>logLevel</code> (i.e. <code>config().logLevel</code> should be valid).<br>
	 * 			If omitted, the default logger will be returned.
	 * @param {String} [logLevel]
	 * 			a name / ID for the logger that should be created / retrieved.
	 * 			If omitted, the default logger will be returned.
	 * 
	 * @returns {Logger} the created (or retrieved) logger
	 * 
	 * @memberOf mmir.Logging.prototype
	 * @public
	 * 
	 * @see Logger
	 * @see Logger#setLevel
	 */
    create: function(loggerName, logLevel){
    	
    	//special argument: is first argument is a (requirejs) module?
    	if(typeof loggerName === 'object' && loggerName && loggerName.id && typeof loggerName.config === 'function'){
    		//extract parameters from module object:
    		logLevel = loggerName.config().logLevel;//<- may be undefined
    		loggerName = loggerName.id;
    	}
    		
        //no logger specified: return default logger
        if(! loggerName){
        	return _defaultLogger;
        }
        
        if(typeof loggerName !== 'string'){
        	loggerName = loggerName.toString();
        }
        
        //return specified logger
        var theLogger = _loggers.get(loggerName);
        if(typeof theLogger === 'undefined'){
        	//create, if not existing
        	var theNewLogger = new Logger(loggerName, logLevel);
        	_loggers.put(loggerName, theNewLogger);
        	
        	return theNewLogger;
        }
        
        if(typeof logLevel !== 'undefined'){
        	theLogger.setLevel(logLevel);
        }
        
        return theLogger;
    },
    /**
     * Sets the default log-level.
     * 
     * This setting is used by loggers, that do not have
     * a specific log-level set.
     * 
     * @param {Number} theLevel
     * 			the log level: a number between 0 (verbose) and 6 (disabled)
     * 
	 * @public
	 * 
	 * @see #getDefaultLogLevel
	 * @see Logger#getLevel
	 */
    setDefaultLogLevel: function(theLevel){
    	_level = theLevel;
    },
    /**
     * Sets the default log-level.
     * 
     * @returns {Number}
     * 			the log level: a number between 0 (verbose) and 6 (disabled)
     * 
	 * @public
	 * @see #setDefaultLogLevel
	 * @see Logger#getLevel
	 */
    getDefaultLogLevel: function(){
    	return _level;
    },
    /**
     * Print log output with default logger.
	 * @public
	 * @see Logger#log
	 */
    log: function(){
    	_defaultLogger.log.apply(_defaultLogger, arguments);
    },
    /**
     * Print verbose output with default logger.
	 * @public
	 * @see Logger#verbose
	 */
    verbose: function(){
    	_defaultLogger.verbose.apply(_defaultLogger, arguments);
    },
    /**
     * Print debug message with default logger.
	 * @public
	 * @see Logger#debug
	 */
    debug: function(){
    	_defaultLogger.debug.apply(_defaultLogger, arguments);
    },
    /**
     * Print information message with default logger.
	 * @public
	 * @see Logger#info
	 */
    info: function(){
    	_defaultLogger.info.apply(_defaultLogger, arguments);
    },
    /**
     * Print warning message with default logger.
	 * @public
	 * @see Logger#warn
	 */
    warn: function(){
    	_defaultLogger.warn.apply(_defaultLogger, arguments);
    },
    /**
     * Print error with default logger.
	 * @public
	 * @see Logger#error
	 */
    error: function(){
    	_defaultLogger.error.apply(_defaultLogger, arguments);
    }//,
//    isDebug : function(loggerName){
//    	return _level <= getAsLevel('debug');
//    },
//    isInfo : function(loggerName){
//    	return _level <= getAsLevel('info');
//    },
//    isWarn : function(loggerName){
//    	return _level <= getAsLevel('warn');
//    },
//    isError : function(loggerName){
//    	return _level <= getAsLevel('error');
//    }
};

//define alias'
instance.get = instance.create;


return instance;
    
});