mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-27 10:57:34 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
932
mailnews/db/gloda/modules/log4moz.js
Normal file
932
mailnews/db/gloda/modules/log4moz.js
Normal file
|
|
@ -0,0 +1,932 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['Log4Moz'];
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var Cu = Components.utils;
|
||||
|
||||
var MODE_RDONLY = 0x01;
|
||||
var MODE_WRONLY = 0x02;
|
||||
var MODE_CREATE = 0x08;
|
||||
var MODE_APPEND = 0x10;
|
||||
var MODE_TRUNCATE = 0x20;
|
||||
|
||||
var PERMS_FILE = parseInt("0644", 8);
|
||||
var PERMS_DIRECTORY = parseInt("0755", 8);
|
||||
|
||||
var ONE_BYTE = 1;
|
||||
var ONE_KILOBYTE = 1024 * ONE_BYTE;
|
||||
var ONE_MEGABYTE = 1024 * ONE_KILOBYTE;
|
||||
|
||||
var DEFAULT_NETWORK_TIMEOUT_DELAY = 5;
|
||||
|
||||
var CDATA_START = "<![CDATA[";
|
||||
var CDATA_END = "]]>";
|
||||
var CDATA_ESCAPED_END = CDATA_END + "]]>" + CDATA_START;
|
||||
|
||||
var Log4Moz = {
|
||||
Level: {
|
||||
Fatal: 70,
|
||||
Error: 60,
|
||||
Warn: 50,
|
||||
Info: 40,
|
||||
Config: 30,
|
||||
Debug: 20,
|
||||
Trace: 10,
|
||||
All: 0,
|
||||
Desc: {
|
||||
70: "FATAL",
|
||||
60: "ERROR",
|
||||
50: "WARN",
|
||||
40: "INFO",
|
||||
30: "CONFIG",
|
||||
20: "DEBUG",
|
||||
10: "TRACE",
|
||||
0: "ALL"
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a logger and configure it with dump and console appenders as
|
||||
* specified by prefs based on the logger name.
|
||||
*
|
||||
* E.g., if the loggername is foo, then look for prefs
|
||||
* foo.logging.console
|
||||
* foo.logging.dump
|
||||
*
|
||||
* whose values can be empty: no logging of that type; or any of
|
||||
* 'Fatal', 'Error', 'Warn', 'Info', 'Config', 'Debug', 'Trace', 'All',
|
||||
* in which case the logging level for each appender will be set accordingly
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* @param loggername The name of the logger
|
||||
* @param level (optional) the level of the logger itself
|
||||
* @param consoleLevel (optional) the level of the console appender
|
||||
* @param dumpLevel (optional) the level of the dump appender
|
||||
*
|
||||
* As described above, well-named prefs override the last two parameters
|
||||
**/
|
||||
|
||||
getConfiguredLogger: function(loggername, level, consoleLevel, dumpLevel) {
|
||||
let log = Log4Moz.repository.getLogger(loggername);
|
||||
if (log._configured)
|
||||
return log
|
||||
|
||||
let formatter = new Log4Moz.BasicFormatter();
|
||||
|
||||
level = level || Log4Moz.Level.Error;
|
||||
|
||||
consoleLevel = consoleLevel || -1;
|
||||
dumpLevel = dumpLevel || -1;
|
||||
let branch = Services.prefs.getBranch(loggername + ".logging.");
|
||||
if (branch)
|
||||
{
|
||||
try {
|
||||
// figure out if event-driven indexing should be enabled...
|
||||
let consoleLevelString = branch.getCharPref("console");
|
||||
if (consoleLevelString) {
|
||||
// capitalize to fit with Log4Moz.Level expectations
|
||||
consoleLevelString = consoleLevelString.charAt(0).toUpperCase() +
|
||||
consoleLevelString.substr(1).toLowerCase();
|
||||
consoleLevel = (consoleLevelString == 'None') ?
|
||||
100 : Log4Moz.Level[consoleLevelString];
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore if preference is not found
|
||||
}
|
||||
try {
|
||||
let dumpLevelString = branch.getCharPref("dump");
|
||||
if (dumpLevelString) {
|
||||
// capitalize to fit with Log4Moz.Level expectations
|
||||
dumpLevelString = dumpLevelString.charAt(0).toUpperCase() +
|
||||
dumpLevelString.substr(1).toLowerCase();
|
||||
dumpLevel = (dumpLevelString == 'None') ?
|
||||
100 : Log4Moz.Level[dumpLevelString];
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore if preference is not found
|
||||
}
|
||||
}
|
||||
|
||||
if (consoleLevel != 100) {
|
||||
if (consoleLevel == -1)
|
||||
consoleLevel = Log4Moz.Level.Error;
|
||||
let capp = new Log4Moz.ConsoleAppender(formatter);
|
||||
capp.level = consoleLevel;
|
||||
log.addAppender(capp);
|
||||
}
|
||||
|
||||
if (dumpLevel != 100) {
|
||||
if (dumpLevel == -1)
|
||||
dumpLevel = Log4Moz.Level.Error;
|
||||
let dapp = new Log4Moz.DumpAppender(formatter);
|
||||
dapp.level = dumpLevel;
|
||||
log.addAppender(dapp);
|
||||
}
|
||||
|
||||
log.level = Math.min(level, Math.min(consoleLevel, dumpLevel));
|
||||
|
||||
log._configured = true;
|
||||
|
||||
return log;
|
||||
},
|
||||
|
||||
get repository() {
|
||||
delete Log4Moz.repository;
|
||||
Log4Moz.repository = new LoggerRepository();
|
||||
return Log4Moz.repository;
|
||||
},
|
||||
set repository(value) {
|
||||
delete Log4Moz.repository;
|
||||
Log4Moz.repository = value;
|
||||
},
|
||||
|
||||
get LogMessage() { return LogMessage; },
|
||||
get Logger() { return Logger; },
|
||||
get LoggerRepository() { return LoggerRepository; },
|
||||
|
||||
get Formatter() { return Formatter; },
|
||||
get BasicFormatter() { return BasicFormatter; },
|
||||
get XMLFormatter() { return XMLFormatter; },
|
||||
get JSONFormatter() { return JSONFormatter; },
|
||||
get Appender() { return Appender; },
|
||||
get DumpAppender() { return DumpAppender; },
|
||||
get ConsoleAppender() { return ConsoleAppender; },
|
||||
get TimeAwareMemoryBucketAppender() { return TimeAwareMemoryBucketAppender; },
|
||||
get FileAppender() { return FileAppender; },
|
||||
get SocketAppender() { return SocketAppender; },
|
||||
get RotatingFileAppender() { return RotatingFileAppender; },
|
||||
get ThrowingAppender() { return ThrowingAppender; },
|
||||
|
||||
// Logging helper:
|
||||
// let logger = Log4Moz.repository.getLogger("foo");
|
||||
// logger.info(Log4Moz.enumerateInterfaces(someObject).join(","));
|
||||
enumerateInterfaces: function Log4Moz_enumerateInterfaces(aObject) {
|
||||
let interfaces = [];
|
||||
|
||||
for (i in Ci) {
|
||||
try {
|
||||
aObject.QueryInterface(Ci[i]);
|
||||
interfaces.push(i);
|
||||
}
|
||||
catch(ex) {}
|
||||
}
|
||||
|
||||
return interfaces;
|
||||
},
|
||||
|
||||
// Logging helper:
|
||||
// let logger = Log4Moz.repository.getLogger("foo");
|
||||
// logger.info(Log4Moz.enumerateProperties(someObject).join(","));
|
||||
enumerateProperties: function Log4Moz_enumerateProps(aObject,
|
||||
aExcludeComplexTypes) {
|
||||
let properties = [];
|
||||
|
||||
for (var p in aObject) {
|
||||
try {
|
||||
if (aExcludeComplexTypes &&
|
||||
(typeof aObject[p] == "object" || typeof aObject[p] == "function"))
|
||||
continue;
|
||||
properties.push(p + " = " + aObject[p]);
|
||||
}
|
||||
catch(ex) {
|
||||
properties.push(p + " = " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
};
|
||||
|
||||
function LoggerContext() {
|
||||
this._started = this._lastStateChange = Date.now();
|
||||
this._state = "started";
|
||||
}
|
||||
LoggerContext.prototype = {
|
||||
_jsonMe: true,
|
||||
_id: "unknown",
|
||||
setState: function LoggerContext_state(aState) {
|
||||
this._state = aState;
|
||||
this._lastStateChange = Date.now();
|
||||
return this;
|
||||
},
|
||||
finish: function LoggerContext_finish() {
|
||||
this._finished = Date.now();
|
||||
this._state = "finished";
|
||||
return this;
|
||||
},
|
||||
toString: function LoggerContext_toString() {
|
||||
return "[Context: " + this._id + " state: " + this._state + "]";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* LogMessage
|
||||
* Encapsulates a single log event's data
|
||||
*/
|
||||
function LogMessage(loggerName, level, messageObjects){
|
||||
this.loggerName = loggerName;
|
||||
this.messageObjects = messageObjects;
|
||||
this.level = level;
|
||||
this.time = Date.now();
|
||||
}
|
||||
LogMessage.prototype = {
|
||||
get levelDesc() {
|
||||
if (this.level in Log4Moz.Level.Desc)
|
||||
return Log4Moz.Level.Desc[this.level];
|
||||
return "UNKNOWN";
|
||||
},
|
||||
|
||||
toString: function LogMsg_toString(){
|
||||
return "LogMessage [" + this.time + " " + this.level + " " +
|
||||
this.messageObjects + "]";
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Logger
|
||||
* Hierarchical version. Logs to all appenders, assigned or inherited
|
||||
*/
|
||||
|
||||
function Logger(name, repository) {
|
||||
this._init(name, repository);
|
||||
}
|
||||
Logger.prototype = {
|
||||
_init: function Logger__init(name, repository) {
|
||||
if (!repository)
|
||||
repository = Log4Moz.repository;
|
||||
this._name = name;
|
||||
this.children = [];
|
||||
this.ownAppenders = [];
|
||||
this.appenders = [];
|
||||
this._repository = repository;
|
||||
},
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
_level: null,
|
||||
get level() {
|
||||
if (this._level != null)
|
||||
return this._level;
|
||||
if (this.parent)
|
||||
return this.parent.level;
|
||||
dump("log4moz warning: root logger configuration error: no level defined\n");
|
||||
return Log4Moz.Level.All;
|
||||
},
|
||||
set level(level) {
|
||||
this._level = level;
|
||||
},
|
||||
|
||||
_parent: null,
|
||||
get parent() { return this._parent; },
|
||||
set parent(parent) {
|
||||
if (this._parent == parent) {
|
||||
return;
|
||||
}
|
||||
// Remove ourselves from parent's children
|
||||
if (this._parent) {
|
||||
let index = this._parent.children.indexOf(this);
|
||||
if (index != -1) {
|
||||
this._parent.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this._parent = parent;
|
||||
parent.children.push(this);
|
||||
this.updateAppenders();
|
||||
},
|
||||
|
||||
updateAppenders: function updateAppenders() {
|
||||
if (this._parent) {
|
||||
let notOwnAppenders = this._parent.appenders.filter(function(appender) {
|
||||
return this.ownAppenders.indexOf(appender) == -1;
|
||||
}, this);
|
||||
this.appenders = notOwnAppenders.concat(this.ownAppenders);
|
||||
} else {
|
||||
this.appenders = this.ownAppenders.slice();
|
||||
}
|
||||
|
||||
// Update children's appenders.
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
this.children[i].updateAppenders();
|
||||
}
|
||||
},
|
||||
|
||||
addAppender: function Logger_addAppender(appender) {
|
||||
if (this.ownAppenders.indexOf(appender) != -1) {
|
||||
return;
|
||||
}
|
||||
this.ownAppenders.push(appender);
|
||||
this.updateAppenders();
|
||||
},
|
||||
|
||||
_nextContextId: 0,
|
||||
newContext: function Logger_newContext(objWithProps) {
|
||||
if (!("_id" in objWithProps))
|
||||
objWithProps._id = this._name + ":" + (++this._nextContextId);
|
||||
|
||||
let c = new LoggerContext();
|
||||
c._isContext = true;
|
||||
for (let key in objWithProps) {
|
||||
c[key] = objWithProps[key];
|
||||
}
|
||||
return c;
|
||||
},
|
||||
|
||||
log: function Logger_log(message) {
|
||||
if (this.level > message.level)
|
||||
return;
|
||||
let appenders = this.appenders;
|
||||
for (let i = 0; i < appenders.length; i++){
|
||||
appenders[i].append(message);
|
||||
}
|
||||
},
|
||||
|
||||
removeAppender: function Logger_removeAppender(appender) {
|
||||
let index = this.ownAppenders.indexOf(appender);
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
this.ownAppenders.splice(index, 1);
|
||||
this.updateAppenders();
|
||||
},
|
||||
|
||||
log: function Logger_log(level, args) {
|
||||
if (this.level > level)
|
||||
return;
|
||||
|
||||
// Hold off on creating the message object until we actually have
|
||||
// an appender that's responsible.
|
||||
let message;
|
||||
let appenders = this.appenders;
|
||||
for (let i = 0; i < appenders.length; i++){
|
||||
let appender = appenders[i];
|
||||
if (appender.level > level)
|
||||
continue;
|
||||
|
||||
if (!message)
|
||||
message = new LogMessage(this._name, level,
|
||||
Array.prototype.slice.call(args));
|
||||
|
||||
appender.append(message);
|
||||
}
|
||||
},
|
||||
|
||||
fatal: function Logger_fatal() {
|
||||
this.log(Log4Moz.Level.Fatal, arguments);
|
||||
},
|
||||
error: function Logger_error() {
|
||||
this.log(Log4Moz.Level.Error, arguments);
|
||||
},
|
||||
warn: function Logger_warn() {
|
||||
this.log(Log4Moz.Level.Warn, arguments);
|
||||
},
|
||||
info: function Logger_info(string) {
|
||||
this.log(Log4Moz.Level.Info, arguments);
|
||||
},
|
||||
config: function Logger_config(string) {
|
||||
this.log(Log4Moz.Level.Config, arguments);
|
||||
},
|
||||
debug: function Logger_debug(string) {
|
||||
this.log(Log4Moz.Level.Debug, arguments);
|
||||
},
|
||||
trace: function Logger_trace(string) {
|
||||
this.log(Log4Moz.Level.Trace, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* LoggerRepository
|
||||
* Implements a hierarchy of Loggers
|
||||
*/
|
||||
|
||||
function LoggerRepository() {}
|
||||
LoggerRepository.prototype = {
|
||||
_loggers: {},
|
||||
|
||||
_rootLogger: null,
|
||||
get rootLogger() {
|
||||
if (!this._rootLogger) {
|
||||
this._rootLogger = new Logger("root", this);
|
||||
this._rootLogger.level = Log4Moz.Level.All;
|
||||
}
|
||||
return this._rootLogger;
|
||||
},
|
||||
set rootLogger(logger) {
|
||||
throw "Cannot change the root logger";
|
||||
},
|
||||
|
||||
_updateParents: function LogRep__updateParents(name) {
|
||||
let pieces = name.split('.');
|
||||
let cur, parent;
|
||||
|
||||
// find the closest parent
|
||||
// don't test for the logger name itself, as there's a chance it's already
|
||||
// there in this._loggers
|
||||
for (let i = 0; i < pieces.length - 1; i++) {
|
||||
if (cur)
|
||||
cur += '.' + pieces[i];
|
||||
else
|
||||
cur = pieces[i];
|
||||
if (cur in this._loggers)
|
||||
parent = cur;
|
||||
}
|
||||
|
||||
// if we didn't assign a parent above, there is no parent
|
||||
if (!parent)
|
||||
this._loggers[name].parent = this.rootLogger;
|
||||
else
|
||||
this._loggers[name].parent = this._loggers[parent];
|
||||
|
||||
// trigger updates for any possible descendants of this logger
|
||||
for (let logger in this._loggers) {
|
||||
if (logger != name && logger.indexOf(name) == 0)
|
||||
this._updateParents(logger);
|
||||
}
|
||||
},
|
||||
|
||||
getLogger: function LogRep_getLogger(name) {
|
||||
if (name in this._loggers)
|
||||
return this._loggers[name];
|
||||
this._loggers[name] = new Logger(name, this);
|
||||
this._updateParents(name);
|
||||
return this._loggers[name];
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Formatters
|
||||
* These massage a LogMessage into whatever output is desired
|
||||
* Only the BasicFormatter is currently implemented
|
||||
*/
|
||||
|
||||
// Abstract formatter
|
||||
function Formatter() {}
|
||||
Formatter.prototype = {
|
||||
format: function Formatter_format(message) {}
|
||||
};
|
||||
|
||||
// services' log4moz lost the date formatting default...
|
||||
function BasicFormatter(dateFormat) {
|
||||
if (dateFormat)
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
BasicFormatter.prototype = {
|
||||
__proto__: Formatter.prototype,
|
||||
|
||||
_dateFormat: null,
|
||||
|
||||
get dateFormat() {
|
||||
if (!this._dateFormat)
|
||||
this._dateFormat = "%Y-%m-%d %H:%M:%S";
|
||||
return this._dateFormat;
|
||||
},
|
||||
|
||||
set dateFormat(format) {
|
||||
this._dateFormat = format;
|
||||
},
|
||||
|
||||
format: function BF_format(message) {
|
||||
let date = new Date(message.time);
|
||||
// The trick below prevents errors further down because mo is null or
|
||||
// undefined.
|
||||
let messageString = message.messageObjects.map(mo => "" + mo).join(" ");
|
||||
return date.toLocaleFormat(this.dateFormat) + "\t" +
|
||||
message.loggerName + "\t" + message.levelDesc + "\t" +
|
||||
messageString + "\n";
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* XMLFormatter
|
||||
* Format like log4j's XMLLayout. The intent is that you can hook this up to
|
||||
* a SocketAppender and point them at a Chainsaw GUI running with an
|
||||
* XMLSocketReceiver running. Then your output comes out in Chainsaw.
|
||||
* (Chainsaw is log4j's GUI that displays log output with niceties such as
|
||||
* filtering and conditional coloring.)
|
||||
*/
|
||||
|
||||
function XMLFormatter() {}
|
||||
XMLFormatter.prototype = {
|
||||
__proto__: Formatter.prototype,
|
||||
|
||||
format: function XF_format(message) {
|
||||
let cdataEscapedMessage =
|
||||
message.messageObjects
|
||||
.map(mo => (typeof(mo) == "object") ? mo.toString() : mo)
|
||||
.join(" ")
|
||||
.split(CDATA_END).join(CDATA_ESCAPED_END);
|
||||
return "<log4j:event logger='" + message.loggerName + "' " +
|
||||
"level='" + message.levelDesc + "' thread='unknown' " +
|
||||
"timestamp='" + message.time + "'>" +
|
||||
"<log4j:message><![CDATA[" + cdataEscapedMessage + "]]></log4j:message>" +
|
||||
"</log4j:event>";
|
||||
}
|
||||
};
|
||||
|
||||
function JSONFormatter() {
|
||||
}
|
||||
JSONFormatter.prototype = {
|
||||
__proto__: Formatter.prototype,
|
||||
|
||||
format: function JF_format(message) {
|
||||
// XXX I did all kinds of questionable things in here; they should be
|
||||
// resolved...
|
||||
// 1) JSON does not walk the __proto__ chain; there is no need to clobber
|
||||
// it.
|
||||
// 2) Our net mutation is sorta redundant messageObjects alongside
|
||||
// msgObjects, although we only serialize one.
|
||||
let origMessageObjects = message.messageObjects;
|
||||
message.messageObjects = [];
|
||||
let reProto = [];
|
||||
for (let messageObject of origMessageObjects) {
|
||||
if (messageObject)
|
||||
if (messageObject._jsonMe) {
|
||||
message.messageObjects.push(messageObject);
|
||||
// FIXME: the commented out code should be fixed in a better way.
|
||||
// See bug 984539: find a good way to avoid JSONing the impl in log4moz
|
||||
// // temporarily strip the prototype to avoid JSONing the impl.
|
||||
// reProto.push([messageObject, messageObject.__proto__]);
|
||||
// messageObject.__proto__ = undefined;
|
||||
}
|
||||
else
|
||||
message.messageObjects.push(messageObject.toString());
|
||||
else
|
||||
message.messageObjects.push(messageObject);
|
||||
}
|
||||
let encoded = JSON.stringify(message) + "\r\n";
|
||||
message.msgObjects = origMessageObjects;
|
||||
// for (let objectAndProtoPair of reProto) {
|
||||
// objectAndProtoPair[0].__proto__ = objectAndProtoPair[1];
|
||||
// }
|
||||
return encoded;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Appenders
|
||||
* These can be attached to Loggers to log to different places
|
||||
* Simply subclass and override doAppend to implement a new one
|
||||
*/
|
||||
|
||||
function Appender(formatter) {
|
||||
this._name = "Appender";
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
}
|
||||
Appender.prototype = {
|
||||
_level: Log4Moz.Level.All,
|
||||
|
||||
append: function App_append(message) {
|
||||
this.doAppend(this._formatter.format(message));
|
||||
},
|
||||
toString: function App_toString() {
|
||||
return this._name + " [level=" + this._level +
|
||||
", formatter=" + this._formatter + "]";
|
||||
},
|
||||
doAppend: function App_doAppend(message) {}
|
||||
};
|
||||
|
||||
/*
|
||||
* DumpAppender
|
||||
* Logs to standard out
|
||||
*/
|
||||
|
||||
function DumpAppender(formatter) {
|
||||
this._name = "DumpAppender";
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
}
|
||||
DumpAppender.prototype = {
|
||||
__proto__: Appender.prototype,
|
||||
|
||||
doAppend: function DApp_doAppend(message) {
|
||||
dump(message);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An in-memory appender that always logs to its in-memory bucket and associates
|
||||
* each message with a timestamp. Whoever creates us is responsible for causing
|
||||
* us to switch to a new bucket using whatever criteria is appropriate.
|
||||
*
|
||||
* This is intended to be used roughly like an in-memory circular buffer. The
|
||||
* expectation is that we are being used for unit tests and that each unit test
|
||||
* function will get its own bucket. In the event that a test fails we would
|
||||
* be asked for the contents of the current bucket and some portion of the
|
||||
* previous bucket using up to some duration.
|
||||
*/
|
||||
function TimeAwareMemoryBucketAppender() {
|
||||
this._name = "TimeAwareMemoryBucketAppender";
|
||||
this._level = Log4Moz.Level.All;
|
||||
|
||||
this._lastBucket = null;
|
||||
// to minimize object construction, even indices are timestamps, odd indices
|
||||
// are the message objects.
|
||||
this._curBucket = [];
|
||||
this._curBucketStartedAt = Date.now();
|
||||
}
|
||||
TimeAwareMemoryBucketAppender.prototype = {
|
||||
get level() { return this._level; },
|
||||
set level(level) { this._level = level; },
|
||||
|
||||
append: function TAMBA_append(message) {
|
||||
if (this._level <= message.level)
|
||||
this._curBucket.push(message);
|
||||
},
|
||||
|
||||
newBucket: function() {
|
||||
this._lastBucket = this._curBucket;
|
||||
this._curBucketStartedAt = Date.now();
|
||||
this._curBucket = [];
|
||||
},
|
||||
|
||||
getPreviousBucketEvents: function(aNumMS) {
|
||||
let lastBucket = this._lastBucket;
|
||||
if (lastBucket == null || !lastBucket.length)
|
||||
return [];
|
||||
let timeBound = this._curBucketStartedAt - aNumMS;
|
||||
// seek backwards through the list...
|
||||
let i;
|
||||
for (i = lastBucket.length - 1; i >= 0; i --) {
|
||||
if (lastBucket[i].time < timeBound)
|
||||
break;
|
||||
}
|
||||
return lastBucket.slice(i+1);
|
||||
},
|
||||
|
||||
getBucketEvents: function() {
|
||||
return this._curBucket.concat();
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return "[TimeAwareMemoryBucketAppender]";
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* ConsoleAppender
|
||||
* Logs to the javascript console
|
||||
*/
|
||||
|
||||
function ConsoleAppender(formatter) {
|
||||
this._name = "ConsoleAppender";
|
||||
this._formatter = formatter;
|
||||
}
|
||||
ConsoleAppender.prototype = {
|
||||
__proto__: Appender.prototype,
|
||||
|
||||
// override to send Error and higher level messages to Components.utils.reportError()
|
||||
append: function CApp_append(message) {
|
||||
let stringMessage = this._formatter.format(message);
|
||||
if (message.level > Log4Moz.Level.Warn) {
|
||||
Cu.reportError(stringMessage);
|
||||
}
|
||||
this.doAppend(stringMessage);
|
||||
},
|
||||
|
||||
doAppend: function CApp_doAppend(message) {
|
||||
Services.console.logStringMessage(message);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* FileAppender
|
||||
* Logs to a file
|
||||
*/
|
||||
|
||||
function FileAppender(file, formatter) {
|
||||
this._name = "FileAppender";
|
||||
this._file = file; // nsIFile
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
}
|
||||
FileAppender.prototype = {
|
||||
__proto__: Appender.prototype,
|
||||
|
||||
__fos: null,
|
||||
get _fos() {
|
||||
if (!this.__fos)
|
||||
this.openStream();
|
||||
return this.__fos;
|
||||
},
|
||||
|
||||
openStream: function FApp_openStream() {
|
||||
this.__fos = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
let flags = MODE_WRONLY | MODE_CREATE | MODE_APPEND;
|
||||
this.__fos.init(this._file, flags, PERMS_FILE, 0);
|
||||
},
|
||||
|
||||
closeStream: function FApp_closeStream() {
|
||||
if (!this.__fos)
|
||||
return;
|
||||
try {
|
||||
this.__fos.close();
|
||||
this.__fos = null;
|
||||
} catch(e) {
|
||||
dump("Failed to close file output stream\n" + e);
|
||||
}
|
||||
},
|
||||
|
||||
doAppend: function FApp_doAppend(message) {
|
||||
if (message === null || message.length <= 0)
|
||||
return;
|
||||
try {
|
||||
this._fos.write(message, message.length);
|
||||
} catch(e) {
|
||||
dump("Error writing file:\n" + e);
|
||||
}
|
||||
},
|
||||
|
||||
clear: function FApp_clear() {
|
||||
this.closeStream();
|
||||
this._file.remove(false);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* RotatingFileAppender
|
||||
* Similar to FileAppender, but rotates logs when they become too large
|
||||
*/
|
||||
|
||||
function RotatingFileAppender(file, formatter, maxSize, maxBackups) {
|
||||
if (maxSize === undefined)
|
||||
maxSize = ONE_MEGABYTE * 2;
|
||||
|
||||
if (maxBackups === undefined)
|
||||
maxBackups = 0;
|
||||
|
||||
this._name = "RotatingFileAppender";
|
||||
this._file = file; // nsIFile
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
this._maxSize = maxSize;
|
||||
this._maxBackups = maxBackups;
|
||||
}
|
||||
RotatingFileAppender.prototype = {
|
||||
__proto__: FileAppender.prototype,
|
||||
|
||||
doAppend: function RFApp_doAppend(message) {
|
||||
if (message === null || message.length <= 0)
|
||||
return;
|
||||
try {
|
||||
this.rotateLogs();
|
||||
this._fos.write(message, message.length);
|
||||
} catch(e) {
|
||||
dump("Error writing file:\n" + e);
|
||||
}
|
||||
},
|
||||
rotateLogs: function RFApp_rotateLogs() {
|
||||
if(this._file.exists() &&
|
||||
this._file.fileSize < this._maxSize)
|
||||
return;
|
||||
|
||||
this.closeStream();
|
||||
|
||||
for (let i = this.maxBackups - 1; i > 0; i--){
|
||||
let backup = this._file.parent.clone();
|
||||
backup.append(this._file.leafName + "." + i);
|
||||
if (backup.exists())
|
||||
backup.moveTo(this._file.parent, this._file.leafName + "." + (i + 1));
|
||||
}
|
||||
|
||||
let cur = this._file.clone();
|
||||
if (cur.exists())
|
||||
cur.moveTo(cur.parent, cur.leafName + ".1");
|
||||
|
||||
// Note: this._file still points to the same file
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* SocketAppender
|
||||
* Logs via TCP to a given host and port. Attempts to automatically reconnect
|
||||
* when the connection drops or cannot be initially re-established. Connection
|
||||
* attempts will happen at most every timeoutDelay seconds (has a sane default
|
||||
* if left blank). Messages are dropped when there is no connection.
|
||||
*/
|
||||
|
||||
function SocketAppender(host, port, formatter, timeoutDelay) {
|
||||
this._name = "SocketAppender";
|
||||
this._host = host;
|
||||
this._port = port;
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
this._timeout_delay = timeoutDelay || DEFAULT_NETWORK_TIMEOUT_DELAY;
|
||||
|
||||
this._socketService = Cc["@mozilla.org/network/socket-transport-service;1"]
|
||||
.getService(Ci.nsISocketTransportService);
|
||||
this._mainThread = Services.tm.mainThread;
|
||||
}
|
||||
SocketAppender.prototype = {
|
||||
__proto__: Appender.prototype,
|
||||
|
||||
__nos: null,
|
||||
get _nos() {
|
||||
if (!this.__nos)
|
||||
this.openStream();
|
||||
return this.__nos;
|
||||
},
|
||||
_nextCheck: 0,
|
||||
openStream: function SApp_openStream() {
|
||||
let now = Date.now();
|
||||
if (now <= this._nextCheck) {
|
||||
return;
|
||||
}
|
||||
this._nextCheck = now + this._timeout_delay * 1000;
|
||||
try {
|
||||
this._transport = this._socketService.createTransport(
|
||||
null, 0, // default socket type
|
||||
this._host, this._port,
|
||||
null); // no proxy
|
||||
this._transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT,
|
||||
this._timeout_delay);
|
||||
// do not set a timeout for TIMEOUT_READ_WRITE. The timeout is not
|
||||
// entirely intuitive; your socket will time out if no one reads or
|
||||
// writes to the socket within the timeout. That, as you can imagine,
|
||||
// is not what we want.
|
||||
this._transport.setEventSink(this, this._mainThread);
|
||||
|
||||
let outputStream = this._transport.openOutputStream(
|
||||
0, // neither blocking nor unbuffered operation is desired
|
||||
0, // default buffer size is fine
|
||||
0 // default buffer count is fine
|
||||
);
|
||||
|
||||
let uniOutputStream = Cc["@mozilla.org/intl/converter-output-stream;1"]
|
||||
.createInstance(Ci.nsIConverterOutputStream);
|
||||
uniOutputStream.init(outputStream, "utf-8", 0, 0x0000);
|
||||
|
||||
this.__nos = uniOutputStream;
|
||||
} catch (ex) {
|
||||
dump("Unexpected SocketAppender connection problem: " +
|
||||
ex.fileName + ":" + ex.lineNumber + ": " + ex + "\n");
|
||||
}
|
||||
},
|
||||
|
||||
closeStream: function SApp_closeStream() {
|
||||
if (!this._transport)
|
||||
return;
|
||||
try {
|
||||
this._connected = false;
|
||||
this._transport = null;
|
||||
let nos = this.__nos;
|
||||
this.__nos = null;
|
||||
nos.close();
|
||||
} catch(e) {
|
||||
// this shouldn't happen, but no one cares
|
||||
}
|
||||
},
|
||||
|
||||
doAppend: function SApp_doAppend(message) {
|
||||
if (message === null || message.length <= 0)
|
||||
return;
|
||||
try {
|
||||
let nos = this._nos;
|
||||
if (nos)
|
||||
nos.writeString(message);
|
||||
} catch(e) {
|
||||
if (this._transport && !this._transport.isAlive()) {
|
||||
this.closeStream();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clear: function SApp_clear() {
|
||||
this.closeStream();
|
||||
},
|
||||
|
||||
/* nsITransportEventSink */
|
||||
onTransportStatus: function SApp_onTransportStatus(aTransport, aStatus,
|
||||
aProgress, aProgressMax) {
|
||||
if (aStatus == 0x804b0004) // STATUS_CONNECTED_TO is not a constant.
|
||||
this._connected = true;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Throws an exception whenever it gets a message. Intended to be used in
|
||||
* automated testing situations where the code would normally log an error but
|
||||
* not die in a fatal manner.
|
||||
*/
|
||||
function ThrowingAppender(thrower, formatter) {
|
||||
this._name = "ThrowingAppender";
|
||||
this._formatter = formatter? formatter : new BasicFormatter();
|
||||
this._thrower = thrower;
|
||||
}
|
||||
ThrowingAppender.prototype = {
|
||||
__proto__: Appender.prototype,
|
||||
|
||||
doAppend: function TApp_doAppend(message) {
|
||||
if (this._thrower)
|
||||
this._thrower(message);
|
||||
else
|
||||
throw message;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue