Log4js - It’s a little different now.
Thanks, Tutorial, Tools March 21st, 2007One of the good parts about including things with scope is that you don’t have to worry about changing them into a more extension-friendly namespace format, which is nice.
So I didn’t have to adapt log4js to get it to play nicely in chrome at all. However, I did have to change it to make it a little more Andy friendly.
Basically, I wanted the log output to hit the console (using dump()) and to look like…
startTime logLevel [fileName:lineNum] message\n
eg.
23/03/07 22:10:11:342 DEBUG [overlay.js:14] A debug message
23/03/07 22:10:12:589 DEBUG [overlay.js:21] Another message
Log4js can’t log to a command prompt using dump(). That was an easy change, we just needed to add another appender, as below.
/**
* Appender writes the logs to the Shell of Firefox when it is launched with
* firefox -console (and has the necessary properties enabled)
* PLEASE NOTE - Only works in Firefox
* @constructor
* @extends Appender
* @param logger log4js instance this appender is attached to
* @author Andrew Mutton
*/
function FirefoxConsoleAppender(logger) {
...
this.layout = new MozStackLayout(true);
}
FirefoxConsoleAppender.superclass = Appender.prototype;
FirefoxConsoleAppender.prototype = {
/**
* @see Appender#doAppend
*/
doAppend: function(loggingEvent) {
dump(this.layout.format(loggingEvent));
},
...
So now we can dump to the console. Notice that there’s a new Layout there too? You probably didn’t, since not many people use log4js I imagine.
The new layout is there to take advantage of the information we can get from Components.stack - notably, line numbers and source files.
/**
* MozStackLayout is a layout that takes advantage of stack data from Mozilla.
*
* startTime logLevel [fileName:lineNum] messagen
*
*
* @constructor
* @extends Layout
* @author Andrew Mutton
*/
function MozStackLayout(showDate) {
this.LINE_SEP = "n";
this.showDate = showDate;
}
MozStackLayout.prototype = {
format: function(loggingEvent) {
if (this.showDate && Log4js.simpledate) {
var d = new Log4js.simpledate.SimpleDate(loggingEvent.startTime.getTime());
return d.toFormattedString("~d/~k/~y ~H:~m:~s:~S") + " " + loggingEvent.level.toString() + " [" + loggingEvent.getStackFileName() + ":" + loggingEvent.getStackLineNum() + "] " + loggingEvent.message + this.LINE_SEP;
} else {
return loggingEvent.level.toString() + " [" + loggingEvent.getStackFileName() + ":" + loggingEvent.getStackLineNum() + "] " + loggingEvent.message + this.LINE_SEP;
}
},
...
this is the bit that uses simpledate: to format the date in a less ugly way than you usually get for free from Javascript. I honestly have no idea why there isn’t a nice date formatter built into the language. It is ridiculous.
There’s a few more changes here as well. I had to change the log() method so that it attempts to get stack data (if it’s available).
log: function(message, logLevel) {
if (Components && Components.stack) {
var stack = Components.stack.caller;
if (stack.toString().indexOf("log4js.js") != -1) {
stack = stack.caller;
}
var loggingEvent = new Log4js.LoggingEvent(this.category, logLevel, message, this, stack.toString());
} else {
var loggingEvent = new Log4js.LoggingEvent(this.category, logLevel, message, this);
}
...
and also LoggingEvent, so that it can give the stack information
getStackFileName : function() {
if (this.stackInfo != null) {
var split = this.stackInfo.split(" :: ");
var fileName = split[1];
if (fileName.lastIndexOf("/") != -1) {
var pathSplit = fileName.split("/");
fileName = pathSplit[pathSplit.length - 1];
}
return fileName
}
return null;
},
getStackLineNum : function() {
if (this.stackInfo != null) {
var split = this.stackInfo.split(" :: ");
var lineNum = split[3].split(" ")[1];
return lineNum;
}
return null;
}
So there you have it. Not very interesting today, but this should be the last infrastructure post. I think we can begin doing things properly now.
I’m very interested in getting log4js to be configurable via a properties files (ala log.properties in log4j). This doesn’t seem too hard, so I may have to check it out. An alternative to log.properties would be to write the configuration in JS. Something like…
logger("booksmarts.log").atLevel("DEBUG")
.withAppender("FirefoxConsoleAppender")
.andLayout("MozStackLayout");
this would be too simple though. Maybe something more elaborate. Who can really say eh?