You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by jm...@apache.org on 2007/02/07 01:47:57 UTC

svn commit: r504408 - /incubator/xap/trunk/codebase/src/xap/log/Logger.js

Author: jmargaris
Date: Tue Feb  6 17:47:56 2007
New Revision: 504408

URL: http://svn.apache.org/viewvc?view=rev&rev=504408
Log:
log4j style logger, the code that actually uses the new logger
is not checked in yet as release is imminent

Added:
    incubator/xap/trunk/codebase/src/xap/log/Logger.js   (with props)

Added: incubator/xap/trunk/codebase/src/xap/log/Logger.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/log/Logger.js?view=auto&rev=504408
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/log/Logger.js (added)
+++ incubator/xap/trunk/codebase/src/xap/log/Logger.js Tue Feb  6 17:47:56 2007
@@ -0,0 +1,573 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed 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.
+ *
+ */
+
+Xap.provide("xap.log.Logger");
+Xap.provide("xap.log.LoggingEvent");
+Xap.provide("xap.log.ConsoleAppender");
+
+Xap.require("xap.util.XapException");
+
+
+/**
+ * @fileoverview 
+ * A logging framework based on log4j.
+ *
+ * @author jmargaris
+ * 
+ */
+ 
+
+/** 
+ * Creates a new Logger with name in the form 'a.b.c.' This constructor should never
+ * be called directly, new Loggers should be obtained by calling
+ * xap.log.Logger.getLogger().
+ * 
+ * @class A logging framework based on log4j. It supports multiple
+ * logs with parents and level inheritance and multiple log
+ * appenders. Currently all logs are additive. Methods names and classes
+ * are the same as in log4j except that some simple getter/setters
+ * are just properties and log level is a simple integer constant
+ * rather than a class.
+ * 
+ * @see xap.log.LoggingEvent
+ * @see xap.log.ConsoleAppender
+ * @see xap.log.AlertAppender
+ *
+ * @constructor
+ * @param {String} logName The name of the logger to create.
+ * @author jmargaris
+ */
+xap.log.Logger = function( logName ){
+	
+	/** @private */
+	this._name = logName;
+	
+	/** @private */
+	this._appenders = [];
+	
+	/** @private a map of child log names to child logs */
+	this._childLogs = {};
+	
+	/** @private level of ancestor tree */
+	this._inheritedLevel = 0;
+	
+	/** @private level specifically set here */
+	this._level = 0;	
+} 
+
+/**
+ * Adds an appender to the log.
+ * @param appender An object with a 'doAppend()' method on it.
+ */
+xap.log.Logger.prototype.addAppender = function(appender){
+	this._appenders.push(appender);
+}
+
+
+/**
+ * Sets the logging level for this logger. 
+ * 
+ * @level One of
+ * xap.log.Logger.TRACE, xap.log.Logger.DEBUG, xap.log.Logger.INFO,
+ * xap.log.Logger.WARN, xap.log.Logger.ERROR, xap.log.Logger.FATAL or
+ * xap.log.Logger.NONE
+ */
+xap.log.Logger.prototype.setLevel = function( level ){
+	this._level = level;
+	
+	//cascade level to children
+	for (var i in this._childLogs){
+		this._childLogs[i]._setParent(this);
+	}
+}
+
+/**
+ * Returns the logging level as set on this logger or
+ * as inherited from the ancestor chain.
+ * 
+ * @return A constant corresponding to one of 
+ * xap.log.Logger.TRACE, xap.log.Logger.DEBUG, xap.log.Logger.INFO,
+ * xap.log.Logger.WARN, xap.log.Logger.ERROR, xap.log.Logger.FATAL or
+ * xap.log.Logger.NONE or zero if the level is not set or inherited.
+ */
+xap.log.Logger.prototype.getEffectiveLevel = function(){
+	return (this._level?this._level:(this._inheritedLevel?this._inheritedLevel:0));
+}
+
+
+/**
+ * Logs a message at the given level with the given message
+ * and optional exception/error/thrown object.
+ * 
+ * @param level A log level constant to log at.
+ * @param {String} message A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.log = function( level, message, exception ){
+	if (level < this.getEffectiveLevel()) return;
+	
+	var loggingEvent = new xap.log.LoggingEvent(this._name,this,
+		new Date(),level,message,exception);
+		
+	//dispatch to appenders and to parent appenders
+	this._dispatchLogEvent(loggingEvent);
+}
+
+/**
+ * Logs a message and optional thrown object at the TRACE level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.trace = function( message, exception ){
+	this.log(xap.log.Logger.TRACE, message, exception);
+}
+
+/**
+ * Logs a message and optional thrown object at the DEBUG level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.debug = function( message, exception ){
+	this.log(xap.log.Logger.DEBUG, message, exception);
+}
+
+/**
+ * Logs a message and optional thrown object at the INFO level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.info = function( message, exception ){
+	this.log(xap.log.Logger.INFO, message, exception);
+}
+
+/**
+ * Logs a message and optional thrown object at the WARN level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.warn = function( message, exception ){
+	this.log(xap.log.Logger.WARN, message, exception);
+}
+
+/**
+ * Logs a message and optional thrown object at the ERROR level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.error = function( message, exception ){
+	this.log(xap.log.Logger.ERROR, message, exception);
+}
+
+/**
+ * Logs a message and optional thrown object at the FATAL level.
+ * 
+ * @param {String} message  A string message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ */
+xap.log.Logger.prototype.fatal = function( message, exception ){
+	this.log(xap.log.Logger.FATAL, message, exception);
+}
+
+/**
+ * Returns true if a message at the given level would be logged
+ * according to the current logging level.
+ * @param level The level to check if the logger is enabled for.
+ * @return {boolean} True if a message at the given level should be logged.
+ */
+xap.log.Logger.prototype.isEnabledFor = function( level ){
+	return (level >= this.getEffectiveLevel());
+}
+
+/**
+ * Returns true if a message would be logged
+ * at the TRACE level.
+ * 
+ * @return {boolean} True if a TRACE message should be logged.
+ */
+xap.log.Logger.prototype.isTrace = function( ){
+	return (xap.log.Logger.TRACE >= this.getEffectiveLevel());
+}
+
+/**
+ * Returns true if a message would be logged
+ * at the DEBUG level.
+ * 
+ * @return {boolean} True if a DEBUG message should be logged.
+ */
+xap.log.Logger.prototype.isDebug = function( ){
+	return (xap.log.Logger.DEBUG >= this.getEffectiveLevel());
+}
+
+/**
+ * Returns true if a message would be logged
+ * at the INFO level.
+ * 
+ * @return {boolean} True if an INFO message should be logged.
+ */
+xap.log.Logger.prototype.isInfo= function( ){
+	return (xap.log.Logger.INFO >= this.getEffectiveLevel());
+}
+
+/**
+ * Returns true if a message would be logged
+ * at the WARN level.
+ * 
+ * @return {boolean} True if a WARN message should be logged.
+ */
+xap.log.Logger.prototype.isWarn = function( ){
+	return (xap.log.Logger.WARN >= this.getEffectiveLevel());
+}
+
+/**
+ * Returns true if a message would be logged
+ * at the ERROR level.
+ * 
+ * @return {boolean} True if an ERROR message should be logged.
+ */
+xap.log.Logger.prototype.isError = function( ){
+	return (xap.log.Logger.ERROR >= this.getEffectiveLevel());
+}
+
+
+/**
+ * Returns true if a message would be logged
+ * at the FATAL level.
+ * 
+ * @return {boolean} True if a FATAL message should be logged.
+ */
+xap.log.Logger.prototype.isFatal = function( ){
+	return (xap.log.Logger.FATAL >= this.getEffectiveLevel());
+}
+
+
+/**
+ * Dispatch a log event to appenders and parent appenders.
+ * @private
+ */
+xap.log.Logger.prototype._dispatchLogEvent = function( loggingEvent){
+	for (var i =0; i<this._appenders.length; i++){
+		this._appenders[i].doAppend(loggingEvent);
+	}
+	
+	//TODO this should be optional, need a way to turn the additivity
+	//off
+	if (this._parent){
+		this._parent._dispatchLogEvent(loggingEvent);
+	}
+}
+
+/**
+ * Sets the parent of this log. This will adjust inheritance of
+ * log levels accordingly.
+ * @private
+ */
+xap.log.Logger.prototype._setParent = function( parentLog ){
+	this._parent = parentLog;
+	
+	//add ourselves to child list
+	parentLog._childLogs[this._name] = this;
+	
+	//inerit level from parent
+	this._inheritedLevel = parentLog.getEffectiveLevel();
+	
+	//cascade inherited level to children
+	for (var i in this._childLogs){
+		this._childLogs[i]._setParent(this);
+	}
+}
+
+
+/**
+ * @private
+ * The root of every other logger
+ */
+xap.log.Logger._rootLog = new xap.log.Logger("root");
+
+/**
+ * 'Hashtable' for quick lookup so we don't have to traverse hierarchy
+ * each time we want a logger.
+ * @private
+ */
+xap.log.Logger._namesToLogs = {};
+
+
+/** Constant for the TRACE level.*/
+xap.log.Logger.TRACE = 1;
+
+/** Constant for the DEBUG level.*/
+xap.log.Logger.DEBUG = 2;
+
+/** Constant for the INFO level.*/
+xap.log.Logger.INFO = 3;
+
+/** Constant for the WARN level.*/
+xap.log.Logger.WARN = 4;
+
+/** Constant for the ERROR level.*/
+xap.log.Logger.ERROR = 5;
+
+/** Constant for the FATAL level.*/
+xap.log.Logger.FATAL = 6;
+
+/** Constant for the NONE level.*/
+xap.log.Logger.NONE = 7;
+
+
+/**
+ * An array indexed by constant with entries being
+ * the logical names of the levels.
+ */
+xap.log.Logger.LEVEL_NAMES = ['','TRACE','DEBUG','INFO','WARN','ERROR','FATAL', 'NONE'];
+
+
+/**
+ * Returns the root logger. All loggers are descendents
+ * of the root logger.
+ * 
+ * @return {xap.log.Logger} The root logger.
+ */
+xap.log.Logger.getRootLogger = function(){
+	return xap.log.Logger._rootLog;
+}
+
+
+/**
+ * Returns a logger of the given name, creating a new one
+ * if it does not exist.
+ * 
+ * @param {String} logName A log name in the form of 'a.b.c'.
+ * @return {xap.log.Logger} A logger of the given name.
+ */
+xap.log.Logger.getLogger = function( logName ){	
+	//see if a.b.c.d already exists, if so return that log.
+	var existingLog = xap.log.Logger._namesToLogs[logName];
+	
+	//if it doesn't, create a.b.c.d, creating parent logs as needed
+	//(for example a.b and a.b.c)
+	//hook up parenting relationship
+	if (!existingLog){
+		var packageNames = logName.split('.');
+		var currentLog = xap.log.Logger._rootLog;
+				
+		for (var i = 0; i<packageNames.length;i++){
+			//look for child log a.b.c of parent log a.b	
+			var childLogName  =  packageNames.slice(0,i+1).join('.');
+			existingLog = currentLog._childLogs[childLogName];
+			
+			//if it doesn't exist we need to create it and hook it up to parent
+			if (!existingLog){
+				existingLog = new xap.log.Logger( childLogName );
+				xap.log.Logger._namesToLogs[childLogName] = existingLog;
+				existingLog._setParent(currentLog);
+			}
+			currentLog = existingLog;
+		}
+	}
+	return existingLog;
+}
+
+
+/** 
+ * Creates a new LoggingEvent. Creation of new LoggingEvents is handled
+ * by the logging framework, users should never need to create
+ * their own LoggingEvents.
+ * 
+ * @class LoggingEvent corresponds to the log4j equivalent with simple
+ * get/set converted to properties.
+ *
+ * @constructor
+ * @param {String} logName The name of the logger that message was logged to.
+ * @param {xap.log.Logger} logger The logger that the message was logged to.
+ * @param {Date} date The date the message was logged.
+ * @param level The log level of the message.
+ * @param {String} message The message to log.
+ * @param exception An optional thrown exception/error object
+ * to accompany the message.
+ * @constructor
+ * @author jmargaris
+ */
+xap.log.LoggingEvent = function( logName, logger, date, level, message, exception ){
+	
+	/** The name of the logger that message was logged to.
+	 * @type String */
+	this.logName = logName;
+	
+	/** The logger that the message was logged to.
+	 * @type xap.log.Logger */
+	this.logger = logger;
+	
+	/** The date the message was logged.
+	 * @type Date */
+	this.date = date;
+	
+	/** The log level of the message.*/
+	this.level = level;
+	
+	/** The message to log.
+	 * @type String */
+	this.message = message;
+	
+	/** An optional thrown exception/error object
+	 * to accompany the message. */
+	this.exception = exception;	
+	
+	/** @private */
+	this._renderedMessage = '[' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds() + ' ' + xap.log.Logger.LEVEL_NAMES[level] + ' ' + logName +'] ' + message;
+	
+	if (exception){
+		this._renderedMessage += ' exception: ' + xap.util.XapException.exceptionToString(exception);
+		
+	} 
+}
+
+/**
+ * Returns a string representing the LoggingEvent as it should be 
+ * rendered to a log.
+ * 
+ * @return {String} A log message in default rendered format.
+ */
+xap.log.LoggingEvent.prototype.getRenderedMessage = function(){
+	return this._renderedMessage;
+}
+
+
+/** 
+  * Creates a new AlertAppender.
+  * 
+  * @class AlertAppender is an appender that reports LoggingEvents
+  * of level ERROR or FATAL as onscreen alerts.
+  *
+  * @constructor
+  * @author jmargaris
+  */
+xap.log.AlertAppender = function(){
+	
+}
+
+/**
+ * Conforms to the appender contract.
+ * @param {xap.log.LoggingEvent} logEvent The event to log.
+ */
+xap.log.AlertAppender.prototype.doAppend = function( logEvent ){
+	if (logEvent.level<xap.log.Logger.ERROR){
+		return;//TODO make configurable what the threshold is??
+	}
+	alert( logEvent.getRenderedMessage() );
+}
+
+/** 
+  * Creates a new ConsoleAppender.
+  * 
+  * @class ConsoleAppender is an appender that reports LoggingEvents
+  * to a div onscreen. At this time multiple ConsoleAppenders
+  * don't work well together.
+  *
+  * @constructor
+  * @author jmargaris
+  */
+xap.log.ConsoleAppender = function(){
+	
+	/** @private cheesy handler that points back here for easy scripting */
+	xap.log.ConsoleAppender._log = this;
+}
+
+
+/**
+ * Conforms to the appender contract.
+ * @param {xap.log.LoggingEvent} logEvent The event to log.
+ */
+xap.log.ConsoleAppender.prototype.doAppend = function( logEvent ){
+	this._logEvent( logEvent.getRenderedMessage(), true);
+}
+
+
+/**
+ * Logs a rendered message.
+ * @private
+ */
+xap.log.ConsoleAppender.prototype._logEvent = function(text){
+	if (!this._logDiv){
+		var l = document.createElement('div');
+		l.style.position = 'absolute';
+	    l.style.right = '5px';
+	    l.style.top = '5px';
+	    l.style.width = '200px';
+	    l.style.height = '350px';
+	    l.style.overflow = 'auto';
+	    l.style.backgroundColor = '#f0f0f0';
+	    l.style.border = '1px solid gray';
+	    l.style.fontSize = '10px';
+	    l.style.padding = '5px';
+	    document.body.appendChild(l);   
+	    this._logDiv = l;	
+	        
+	}
+	this._logDiv.style.display = "block";  	
+	
+	//the way this works is extremely wacky
+	//and probably won't work for multiple console logs
+	if(this._logDiv.innerHTML == "") 
+		this._logDiv.innerHTML="<A HREF=\"javascript:xap.log.ConsoleAppender._log._clear()\">Clear</A><br/><A HREF=\"javascript:xap.log.ConsoleAppender._log._resizeOutput(true)\">Bigger</A> | <A HREF=\"javascript:xap.log.ConsoleAppender._log._resizeOutput(false)\">Smaller</A>";        
+	
+	//we used to keep appending to inner HTML here but that was super expensive
+	//although it did allow nice formatting
+	this._logDiv.appendChild(document.createElement('br')); 
+	this._logDiv.appendChild(document.createElement('br')); 
+	this._logDiv.appendChild(document.createTextNode(text));
+	
+	this._logDiv.scrollTop = this._logDiv.scrollHeight;
+		
+}
+
+/**
+ * Makes the log window bigger/smaller.
+ * @private
+ */
+xap.log.ConsoleAppender.prototype._resizeOutput = function(bigger){
+	if(bigger){
+		this._logDiv.style.width = (parseInt(this._logDiv.style.width) + 100) + "px";
+		this._logDiv.style.height = (parseInt(this._logDiv.style.height) + 100) + "px";
+	}
+	else{
+		this._logDiv.style.width = Math.max(parseInt(this._logDiv.style.width) - 100, 150) + "px";
+		this._logDiv.style.height = Math.max(parseInt(this._logDiv.style.height) - 100, 100) + "px";
+	}
+}
+
+
+/**
+ * Clears and hides the log window.
+ * @private
+ */
+xap.log.ConsoleAppender.prototype._clear = function(){
+	if (this._logDiv){
+		this._logDiv.style.display = "none";
+		this._logDiv.innerHTML = "" ;	
+	}
+}

Propchange: incubator/xap/trunk/codebase/src/xap/log/Logger.js
------------------------------------------------------------------------------
    svn:eol-style = native