init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
12
gruntfile.js
Normal file
12
gruntfile.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = function(grunt) {
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
browserify: {
|
||||
'output.js': ['main.js'],
|
||||
options: {
|
||||
transform: ['babelify']
|
||||
}
|
||||
}
|
||||
})
|
||||
grunt.loadNpmTasks('grunt-browserify')
|
||||
}
|
||||
798
jsnlog.js
Normal file
798
jsnlog.js
Normal file
@@ -0,0 +1,798 @@
|
||||
var __extends = this.__extends || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
__.prototype = b.prototype;
|
||||
d.prototype = new __();
|
||||
};
|
||||
function JL(loggerName) {
|
||||
// If name is empty, return the root logger
|
||||
if (!loggerName) {
|
||||
return JL.__;
|
||||
}
|
||||
// Implements Array.reduce. JSNLog supports IE8+ and reduce is not supported in that browser.
|
||||
// Same interface as the standard reduce, except that
|
||||
if (!Array.prototype.reduce) {
|
||||
Array.prototype.reduce = function (callback, initialValue) {
|
||||
var previousValue = initialValue;
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
previousValue = callback(previousValue, this[i], i, this);
|
||||
}
|
||||
return previousValue;
|
||||
};
|
||||
}
|
||||
var accumulatedLoggerName = '';
|
||||
var logger = ('.' + loggerName).split('.').reduce(function (prev, curr, idx, arr) {
|
||||
// if loggername is a.b.c, than currentLogger will be set to the loggers
|
||||
// root (prev: JL, curr: '')
|
||||
// a (prev: JL.__, curr: 'a')
|
||||
// a.b (prev: JL.__.__a, curr: 'b')
|
||||
// a.b.c (prev: JL.__.__a.__a.b, curr: 'c')
|
||||
// Note that when a new logger name is encountered (such as 'a.b.c'),
|
||||
// a new logger object is created and added as a property to the parent ('a.b').
|
||||
// The root logger is added as a property of the JL object itself.
|
||||
// It is essential that the name of the property containing the child logger
|
||||
// contains the full 'path' name of the child logger ('a.b.c') instead of
|
||||
// just the bit after the last period ('c').
|
||||
// This is because the parent inherits properties from its ancestors.
|
||||
// So if the root has a child logger 'c' (stored in a property 'c' of the root logger),
|
||||
// then logger 'a.b' has that same property 'c' through inheritance.
|
||||
// The names of the logger properties start with __, so the root logger
|
||||
// (which has name ''), has a nice property name '__'.
|
||||
// accumulatedLoggerName evaluates false ('' is falsy) in first iteration when prev is the root logger.
|
||||
// accumulatedLoggerName will be the logger name corresponding with the logger in currentLogger.
|
||||
// Keep in mind that the currentLogger may not be defined yet, so can't get the name from
|
||||
// the currentLogger object itself.
|
||||
if (accumulatedLoggerName) {
|
||||
accumulatedLoggerName += '.' + curr;
|
||||
}
|
||||
else {
|
||||
accumulatedLoggerName = curr;
|
||||
}
|
||||
var currentLogger = prev['__' + accumulatedLoggerName];
|
||||
// If the currentLogger (or the actual logger being sought) does not yet exist,
|
||||
// create it now.
|
||||
if (currentLogger === undefined) {
|
||||
// Set the prototype of the Logger constructor function to the parent of the logger
|
||||
// to be created. This way, __proto of the new logger object will point at the parent.
|
||||
// When logger.level is evaluated and is not present, the JavaScript runtime will
|
||||
// walk down the prototype chain to find the first ancestor with a level property.
|
||||
//
|
||||
// Note that prev at this point refers to the parent logger.
|
||||
JL.Logger.prototype = prev;
|
||||
currentLogger = new JL.Logger(accumulatedLoggerName);
|
||||
prev['__' + accumulatedLoggerName] = currentLogger;
|
||||
}
|
||||
return currentLogger;
|
||||
}, JL.__);
|
||||
return logger;
|
||||
}
|
||||
var JL;
|
||||
(function (JL) {
|
||||
JL.enabled;
|
||||
JL.maxMessages;
|
||||
JL.defaultAjaxUrl;
|
||||
JL.clientIP;
|
||||
JL.defaultBeforeSend;
|
||||
// Initialise requestId to empty string. If you don't do this and the user
|
||||
// does not set it via setOptions, then the JSNLog-RequestId header will
|
||||
// have value "undefined", which doesn't look good in a log.
|
||||
//
|
||||
// Note that you always want to send a requestId as part of log requests,
|
||||
// otherwise the server side component doesn't know this is a log request
|
||||
// and may create a new request id for the log request, causing confusion
|
||||
// in the log.
|
||||
JL.requestId = '';
|
||||
/**
|
||||
Copies the value of a property from one object to the other.
|
||||
This is used to copy property values as part of setOption for loggers and appenders.
|
||||
Because loggers inherit property values from their parents, it is important never to
|
||||
create a property on a logger if the intent is to inherit from the parent.
|
||||
Copying rules:
|
||||
1) if the from property is undefined (for example, not mentioned in a JSON object), the
|
||||
to property is not affected at all.
|
||||
2) if the from property is null, the to property is deleted (so the logger will inherit from
|
||||
its parent).
|
||||
3) Otherwise, the from property is copied to the to property.
|
||||
*/
|
||||
function copyProperty(propertyName, from, to) {
|
||||
if (from[propertyName] === undefined) {
|
||||
return;
|
||||
}
|
||||
if (from[propertyName] === null) {
|
||||
delete to[propertyName];
|
||||
return;
|
||||
}
|
||||
to[propertyName] = from[propertyName];
|
||||
}
|
||||
/**
|
||||
Returns true if a log should go ahead.
|
||||
Does not check level.
|
||||
@param filters
|
||||
Filters that determine whether a log can go ahead.
|
||||
*/
|
||||
function allow(filters) {
|
||||
// If enabled is not null or undefined, then if it is false, then return false
|
||||
// Note that undefined==null (!)
|
||||
if (!(JL.enabled == null)) {
|
||||
if (!JL.enabled) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If maxMessages is not null or undefined, then if it is 0, then return false.
|
||||
// Note that maxMessages contains number of messages that are still allowed to send.
|
||||
// It is decremented each time messages are sent. It can be negative when batch size > 1.
|
||||
// Note that undefined==null (!)
|
||||
if (!(JL.maxMessages == null)) {
|
||||
if (JL.maxMessages < 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (filters.userAgentRegex) {
|
||||
if (!new RegExp(filters.userAgentRegex).test(navigator.userAgent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
try {
|
||||
if (filters.ipRegex && JL.clientIP) {
|
||||
if (!new RegExp(filters.ipRegex).test(JL.clientIP)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
Returns true if a log should go ahead, based on the message.
|
||||
@param filters
|
||||
Filters that determine whether a log can go ahead.
|
||||
@param message
|
||||
Message to be logged.
|
||||
*/
|
||||
function allowMessage(filters, message) {
|
||||
// If the regex contains a bug, that will throw an exception.
|
||||
// Ignore this, and pass the log item (better too much than too little).
|
||||
try {
|
||||
if (filters.disallow) {
|
||||
if (new RegExp(filters.disallow).test(message)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// If logObject is a function, the function is evaluated (without parameters)
|
||||
// and the result returned.
|
||||
// Otherwise, logObject itself is returned.
|
||||
function stringifyLogObjectFunction(logObject) {
|
||||
if (typeof logObject == "function") {
|
||||
if (logObject instanceof RegExp) {
|
||||
return logObject.toString();
|
||||
}
|
||||
else {
|
||||
return logObject();
|
||||
}
|
||||
}
|
||||
return logObject;
|
||||
}
|
||||
var StringifiedLogObject = (function () {
|
||||
// * msg -
|
||||
// if the logObject is a scalar (after possible function evaluation), this is set to
|
||||
// string representing the scalar. Otherwise it is left undefined.
|
||||
// * meta -
|
||||
// if the logObject is an object (after possible function evaluation), this is set to
|
||||
// that object. Otherwise it is left undefined.
|
||||
// * finalString -
|
||||
// This is set to the string representation of logObject (after possible function evaluation),
|
||||
// regardless of whether it is an scalar or an object. An object is stringified to a JSON string.
|
||||
// Note that you can't call this field "final", because as some point this was a reserved
|
||||
// JavaScript keyword and using final trips up some minifiers.
|
||||
function StringifiedLogObject(msg, meta, finalString) {
|
||||
this.msg = msg;
|
||||
this.meta = meta;
|
||||
this.finalString = finalString;
|
||||
}
|
||||
return StringifiedLogObject;
|
||||
})();
|
||||
// Takes a logObject, which can be
|
||||
// * a scalar
|
||||
// * an object
|
||||
// * a parameterless function, which returns the scalar or object to log.
|
||||
// Returns a stringifiedLogObject
|
||||
function stringifyLogObject(logObject) {
|
||||
// Note that this works if logObject is null.
|
||||
// typeof null is object.
|
||||
// JSON.stringify(null) returns "null".
|
||||
var actualLogObject = stringifyLogObjectFunction(logObject);
|
||||
var finalString;
|
||||
switch (typeof actualLogObject) {
|
||||
case "string":
|
||||
return new StringifiedLogObject(actualLogObject, null, actualLogObject);
|
||||
case "number":
|
||||
finalString = actualLogObject.toString();
|
||||
return new StringifiedLogObject(finalString, null, finalString);
|
||||
case "boolean":
|
||||
finalString = actualLogObject.toString();
|
||||
return new StringifiedLogObject(finalString, null, finalString);
|
||||
case "undefined":
|
||||
return new StringifiedLogObject("undefined", null, "undefined");
|
||||
case "object":
|
||||
if ((actualLogObject instanceof RegExp) || (actualLogObject instanceof String) || (actualLogObject instanceof Number) || (actualLogObject instanceof Boolean)) {
|
||||
finalString = actualLogObject.toString();
|
||||
return new StringifiedLogObject(finalString, null, finalString);
|
||||
}
|
||||
else {
|
||||
return new StringifiedLogObject(null, actualLogObject, JSON.stringify(actualLogObject));
|
||||
}
|
||||
default:
|
||||
return new StringifiedLogObject("unknown", null, "unknown");
|
||||
}
|
||||
}
|
||||
function setOptions(options) {
|
||||
copyProperty("enabled", options, this);
|
||||
copyProperty("maxMessages", options, this);
|
||||
copyProperty("defaultAjaxUrl", options, this);
|
||||
copyProperty("clientIP", options, this);
|
||||
copyProperty("requestId", options, this);
|
||||
copyProperty("defaultBeforeSend", options, this);
|
||||
return this;
|
||||
}
|
||||
JL.setOptions = setOptions;
|
||||
function getAllLevel() {
|
||||
return -2147483648;
|
||||
}
|
||||
JL.getAllLevel = getAllLevel;
|
||||
function getTraceLevel() {
|
||||
return 1000;
|
||||
}
|
||||
JL.getTraceLevel = getTraceLevel;
|
||||
function getDebugLevel() {
|
||||
return 2000;
|
||||
}
|
||||
JL.getDebugLevel = getDebugLevel;
|
||||
function getInfoLevel() {
|
||||
return 3000;
|
||||
}
|
||||
JL.getInfoLevel = getInfoLevel;
|
||||
function getWarnLevel() {
|
||||
return 4000;
|
||||
}
|
||||
JL.getWarnLevel = getWarnLevel;
|
||||
function getErrorLevel() {
|
||||
return 5000;
|
||||
}
|
||||
JL.getErrorLevel = getErrorLevel;
|
||||
function getFatalLevel() {
|
||||
return 6000;
|
||||
}
|
||||
JL.getFatalLevel = getFatalLevel;
|
||||
function getOffLevel() {
|
||||
return 2147483647;
|
||||
}
|
||||
JL.getOffLevel = getOffLevel;
|
||||
function levelToString(level) {
|
||||
if (level <= 1000) {
|
||||
return "trace";
|
||||
}
|
||||
if (level <= 2000) {
|
||||
return "debug";
|
||||
}
|
||||
if (level <= 3000) {
|
||||
return "info";
|
||||
}
|
||||
if (level <= 4000) {
|
||||
return "warn";
|
||||
}
|
||||
if (level <= 5000) {
|
||||
return "error";
|
||||
}
|
||||
return "fatal";
|
||||
}
|
||||
// ---------------------
|
||||
var Exception = (function () {
|
||||
// data replaces message. It takes not just strings, but also objects and functions, just like the log function.
|
||||
// internally, the string representation is stored in the message property (inherited from Error)
|
||||
//
|
||||
// inner: inner exception. Can be null or undefined.
|
||||
function Exception(data, inner) {
|
||||
this.inner = inner;
|
||||
this.name = "JL.Exception";
|
||||
this.message = stringifyLogObject(data).finalString;
|
||||
}
|
||||
return Exception;
|
||||
})();
|
||||
JL.Exception = Exception;
|
||||
// Derive Exception from Error (a Host object), so browsers
|
||||
// are more likely to produce a stack trace for it in their console.
|
||||
//
|
||||
// Note that instanceof against an object created with this constructor
|
||||
// will return true in these cases:
|
||||
// <object> instanceof JL.Exception);
|
||||
// <object> instanceof Error);
|
||||
Exception.prototype = new Error();
|
||||
// ---------------------
|
||||
var LogItem = (function () {
|
||||
// l: level
|
||||
// m: message
|
||||
// n: logger name
|
||||
// t (timeStamp) is number of milliseconds since 1 January 1970 00:00:00 UTC
|
||||
//
|
||||
// Keeping the property names really short, because they will be sent in the
|
||||
// JSON payload to the server.
|
||||
function LogItem(l, m, n, t) {
|
||||
this.l = l;
|
||||
this.m = m;
|
||||
this.n = n;
|
||||
this.t = t;
|
||||
}
|
||||
return LogItem;
|
||||
})();
|
||||
JL.LogItem = LogItem;
|
||||
// ---------------------
|
||||
var Appender = (function () {
|
||||
// sendLogItems takes an array of log items. It will be called when
|
||||
// the appender has items to process (such as, send to the server).
|
||||
// Note that after sendLogItems returns, the appender may truncate
|
||||
// the LogItem array, so the function has to copy the content of the array
|
||||
// in some fashion (eg. serialize) before returning.
|
||||
function Appender(appenderName, sendLogItems) {
|
||||
this.appenderName = appenderName;
|
||||
this.sendLogItems = sendLogItems;
|
||||
this.level = JL.getTraceLevel();
|
||||
// set to super high level, so if user increases level, level is unlikely to get
|
||||
// above sendWithBufferLevel
|
||||
this.sendWithBufferLevel = 2147483647;
|
||||
this.storeInBufferLevel = -2147483648;
|
||||
this.bufferSize = 0; // buffering switch off by default
|
||||
this.batchSize = 1;
|
||||
// Holds all log items with levels higher than storeInBufferLevel
|
||||
// but lower than level. These items may never be sent.
|
||||
this.buffer = [];
|
||||
// Holds all items that we do want to send, until we have a full
|
||||
// batch (as determined by batchSize).
|
||||
this.batchBuffer = [];
|
||||
}
|
||||
Appender.prototype.setOptions = function (options) {
|
||||
copyProperty("level", options, this);
|
||||
copyProperty("ipRegex", options, this);
|
||||
copyProperty("userAgentRegex", options, this);
|
||||
copyProperty("disallow", options, this);
|
||||
copyProperty("sendWithBufferLevel", options, this);
|
||||
copyProperty("storeInBufferLevel", options, this);
|
||||
copyProperty("bufferSize", options, this);
|
||||
copyProperty("batchSize", options, this);
|
||||
if (this.bufferSize < this.buffer.length) {
|
||||
this.buffer.length = this.bufferSize;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
Called by a logger to log a log item.
|
||||
If in response to this call one or more log items need to be processed
|
||||
(eg., sent to the server), this method calls this.sendLogItems
|
||||
with an array with all items to be processed.
|
||||
Note that the name and parameters of this function must match those of the log function of
|
||||
a Winston transport object, so that users can use these transports as appenders.
|
||||
That is why there are many parameters that are not actually used by this function.
|
||||
level - string with the level ("trace", "debug", etc.) Only used by Winston transports.
|
||||
msg - human readable message. Undefined if the log item is an object. Only used by Winston transports.
|
||||
meta - log object. Always defined, because at least it contains the logger name. Only used by Winston transports.
|
||||
callback - function that is called when the log item has been logged. Only used by Winston transports.
|
||||
levelNbr - level as a number. Not used by Winston transports.
|
||||
message - log item. If the user logged an object, this is the JSON string. Not used by Winston transports.
|
||||
loggerName: name of the logger. Not used by Winston transports.
|
||||
*/
|
||||
Appender.prototype.log = function (level, msg, meta, callback, levelNbr, message, loggerName) {
|
||||
var logItem;
|
||||
if (!allow(this)) {
|
||||
return;
|
||||
}
|
||||
if (!allowMessage(this, message)) {
|
||||
return;
|
||||
}
|
||||
if (levelNbr < this.storeInBufferLevel) {
|
||||
// Ignore the log item completely
|
||||
return;
|
||||
}
|
||||
logItem = new LogItem(levelNbr, message, loggerName, (new Date).getTime());
|
||||
if (levelNbr < this.level) {
|
||||
// Store in the hold buffer. Do not send.
|
||||
if (this.bufferSize > 0) {
|
||||
this.buffer.push(logItem);
|
||||
// If we exceeded max buffer size, remove oldest item
|
||||
if (this.buffer.length > this.bufferSize) {
|
||||
this.buffer.shift();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (levelNbr < this.sendWithBufferLevel) {
|
||||
// Want to send the item, but not the contents of the buffer
|
||||
this.batchBuffer.push(logItem);
|
||||
}
|
||||
else {
|
||||
// Want to send both the item and the contents of the buffer.
|
||||
// Send contents of buffer first, because logically they happened first.
|
||||
if (this.buffer.length) {
|
||||
this.batchBuffer = this.batchBuffer.concat(this.buffer);
|
||||
this.buffer.length = 0;
|
||||
}
|
||||
this.batchBuffer.push(logItem);
|
||||
}
|
||||
if (this.batchBuffer.length >= this.batchSize) {
|
||||
this.sendBatch();
|
||||
return;
|
||||
}
|
||||
};
|
||||
// Processes the batch buffer
|
||||
Appender.prototype.sendBatch = function () {
|
||||
if (this.batchBuffer.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (!(JL.maxMessages == null)) {
|
||||
if (JL.maxMessages < 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If maxMessages is not null or undefined, then decrease it by the batch size.
|
||||
// This can result in a negative maxMessages.
|
||||
// Note that undefined==null (!)
|
||||
if (!(JL.maxMessages == null)) {
|
||||
JL.maxMessages -= this.batchBuffer.length;
|
||||
}
|
||||
this.sendLogItems(this.batchBuffer);
|
||||
this.batchBuffer.length = 0;
|
||||
};
|
||||
return Appender;
|
||||
})();
|
||||
JL.Appender = Appender;
|
||||
// ---------------------
|
||||
var AjaxAppender = (function (_super) {
|
||||
__extends(AjaxAppender, _super);
|
||||
function AjaxAppender(appenderName) {
|
||||
_super.call(this, appenderName, AjaxAppender.prototype.sendLogItemsAjax);
|
||||
}
|
||||
AjaxAppender.prototype.setOptions = function (options) {
|
||||
copyProperty("url", options, this);
|
||||
copyProperty("beforeSend", options, this);
|
||||
_super.prototype.setOptions.call(this, options);
|
||||
return this;
|
||||
};
|
||||
AjaxAppender.prototype.sendLogItemsAjax = function (logItems) {
|
||||
try {
|
||||
// Only determine the url right before you send a log request.
|
||||
// Do not set the url when constructing the appender.
|
||||
//
|
||||
// This is because the server side component sets defaultAjaxUrl
|
||||
// in a call to setOptions, AFTER the JL object and the default appender
|
||||
// have been created.
|
||||
var ajaxUrl = "/jsnlog.logger";
|
||||
// This evaluates to true if defaultAjaxUrl is null or undefined
|
||||
if (!(JL.defaultAjaxUrl == null)) {
|
||||
ajaxUrl = JL.defaultAjaxUrl;
|
||||
}
|
||||
if (this.url) {
|
||||
ajaxUrl = this.url;
|
||||
}
|
||||
var json = JSON.stringify({
|
||||
r: JL.requestId,
|
||||
lg: logItems
|
||||
});
|
||||
// Send the json to the server.
|
||||
// Note that there is no event handling here. If the send is not
|
||||
// successful, nothing can be done about it.
|
||||
var xhr = this.getXhr(ajaxUrl);
|
||||
// call beforeSend callback
|
||||
// first try the callback on the appender
|
||||
// then the global defaultBeforeSend callback
|
||||
if (typeof this.beforeSend === 'function') {
|
||||
this.beforeSend(xhr);
|
||||
}
|
||||
else if (typeof JL.defaultBeforeSend === 'function') {
|
||||
JL.defaultBeforeSend(xhr);
|
||||
}
|
||||
xhr.send(json);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
};
|
||||
// Creates the Xhr object to use to send the log request.
|
||||
// Sets out to create an Xhr object that can be used for CORS.
|
||||
// However, if there seems to be no CORS support on the browser,
|
||||
// returns a non-CORS capable Xhr.
|
||||
AjaxAppender.prototype.getXhr = function (ajaxUrl) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
// Check whether this xhr is CORS capable by checking whether it has
|
||||
// withCredentials.
|
||||
// "withCredentials" only exists on XMLHTTPRequest2 objects.
|
||||
if (!("withCredentials" in xhr)) {
|
||||
// Just found that no XMLHttpRequest2 available.
|
||||
// Check if XDomainRequest is available.
|
||||
// This only exists in IE, and is IE's way of making CORS requests.
|
||||
if (typeof XDomainRequest != "undefined") {
|
||||
// Note that here we're not setting request headers on the XDomainRequest
|
||||
// object. This is because this object doesn't let you do that:
|
||||
// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
|
||||
// This means that for IE8 and IE9, CORS logging requests do not carry request ids.
|
||||
var xdr = new XDomainRequest();
|
||||
xdr.open('POST', ajaxUrl);
|
||||
return xdr;
|
||||
}
|
||||
}
|
||||
// At this point, we're going with XMLHttpRequest, whether it is CORS capable or not.
|
||||
// If it is not CORS capable, at least will handle the non-CORS requests.
|
||||
xhr.open('POST', ajaxUrl);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.setRequestHeader('JSNLog-RequestId', JL.requestId);
|
||||
return xhr;
|
||||
};
|
||||
return AjaxAppender;
|
||||
})(Appender);
|
||||
JL.AjaxAppender = AjaxAppender;
|
||||
// ---------------------
|
||||
var ConsoleAppender = (function (_super) {
|
||||
__extends(ConsoleAppender, _super);
|
||||
function ConsoleAppender(appenderName) {
|
||||
_super.call(this, appenderName, ConsoleAppender.prototype.sendLogItemsConsole);
|
||||
}
|
||||
ConsoleAppender.prototype.clog = function (logEntry) {
|
||||
console.log(logEntry);
|
||||
};
|
||||
ConsoleAppender.prototype.cerror = function (logEntry) {
|
||||
if (console.error) {
|
||||
console.error(logEntry);
|
||||
}
|
||||
else {
|
||||
this.clog(logEntry);
|
||||
}
|
||||
};
|
||||
ConsoleAppender.prototype.cwarn = function (logEntry) {
|
||||
if (console.warn) {
|
||||
console.warn(logEntry);
|
||||
}
|
||||
else {
|
||||
this.clog(logEntry);
|
||||
}
|
||||
};
|
||||
ConsoleAppender.prototype.cinfo = function (logEntry) {
|
||||
if (console.info) {
|
||||
console.info(logEntry);
|
||||
}
|
||||
else {
|
||||
this.clog(logEntry);
|
||||
}
|
||||
};
|
||||
// IE11 has a console.debug function. But its console doesn't have
|
||||
// the option to show/hide debug messages (the same way Chrome and FF do),
|
||||
// even though it does have such buttons for Error, Warn, Info.
|
||||
//
|
||||
// For now, this means that debug messages can not be hidden on IE.
|
||||
// Live with this, seeing that it works fine on FF and Chrome, which
|
||||
// will be much more popular with developers.
|
||||
ConsoleAppender.prototype.cdebug = function (logEntry) {
|
||||
if (console.debug) {
|
||||
console.debug(logEntry);
|
||||
}
|
||||
else {
|
||||
this.cinfo(logEntry);
|
||||
}
|
||||
};
|
||||
ConsoleAppender.prototype.sendLogItemsConsole = function (logItems) {
|
||||
try {
|
||||
if (!console) {
|
||||
return;
|
||||
}
|
||||
var i;
|
||||
for (i = 0; i < logItems.length; ++i) {
|
||||
var li = logItems[i];
|
||||
var msg = li.n + ": " + li.m;
|
||||
// Only log the timestamp if we're on the server
|
||||
// (window is undefined). On the browser, the user
|
||||
// sees the log entry probably immediately, so in that case
|
||||
// the timestamp is clutter.
|
||||
if (typeof window === 'undefined') {
|
||||
msg = new Date(li.t) + " | " + msg;
|
||||
}
|
||||
if (li.l <= JL.getDebugLevel()) {
|
||||
this.cdebug(msg);
|
||||
}
|
||||
else if (li.l <= JL.getInfoLevel()) {
|
||||
this.cinfo(msg);
|
||||
}
|
||||
else if (li.l <= JL.getWarnLevel()) {
|
||||
this.cwarn(msg);
|
||||
}
|
||||
else {
|
||||
this.cerror(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
};
|
||||
return ConsoleAppender;
|
||||
})(Appender);
|
||||
JL.ConsoleAppender = ConsoleAppender;
|
||||
// --------------------
|
||||
var Logger = (function () {
|
||||
function Logger(loggerName) {
|
||||
this.loggerName = loggerName;
|
||||
// Create seenRexes, otherwise this logger will use the seenRexes
|
||||
// of its parent via the prototype chain.
|
||||
this.seenRegexes = [];
|
||||
}
|
||||
Logger.prototype.setOptions = function (options) {
|
||||
copyProperty("level", options, this);
|
||||
copyProperty("userAgentRegex", options, this);
|
||||
copyProperty("disallow", options, this);
|
||||
copyProperty("ipRegex", options, this);
|
||||
copyProperty("appenders", options, this);
|
||||
copyProperty("onceOnly", options, this);
|
||||
// Reset seenRegexes, in case onceOnly has been changed.
|
||||
this.seenRegexes = [];
|
||||
return this;
|
||||
};
|
||||
// Turns an exception into an object that can be sent to the server.
|
||||
Logger.prototype.buildExceptionObject = function (e) {
|
||||
var excObject = {};
|
||||
if (e.stack) {
|
||||
excObject.stack = e.stack;
|
||||
}
|
||||
else {
|
||||
excObject.e = e;
|
||||
}
|
||||
if (e.message) {
|
||||
excObject.message = e.message;
|
||||
}
|
||||
if (e.name) {
|
||||
excObject.name = e.name;
|
||||
}
|
||||
if (e.data) {
|
||||
excObject.data = e.data;
|
||||
}
|
||||
if (e.inner) {
|
||||
excObject.inner = this.buildExceptionObject(e.inner);
|
||||
}
|
||||
return excObject;
|
||||
};
|
||||
// Logs a log item.
|
||||
// Parameter e contains an exception (or null or undefined).
|
||||
//
|
||||
// Reason that processing exceptions is done at this low level is that
|
||||
// 1) no need to spend the cpu cycles if the logger is switched off
|
||||
// 2) fatalException takes both a logObject and an exception, and the logObject
|
||||
// may be a function that should only be executed if the logger is switched on.
|
||||
//
|
||||
// If an exception is passed in, the contents of logObject is attached to the exception
|
||||
// object in a new property logData.
|
||||
// The resulting exception object is than worked into a message to the server.
|
||||
//
|
||||
// If there is no exception, logObject itself is worked into the message to the server.
|
||||
Logger.prototype.log = function (level, logObject, e) {
|
||||
var i = 0;
|
||||
var compositeMessage;
|
||||
var excObject;
|
||||
// If we can't find any appenders, do nothing
|
||||
if (!this.appenders) {
|
||||
return this;
|
||||
}
|
||||
if (((level >= this.level)) && allow(this)) {
|
||||
if (e) {
|
||||
excObject = this.buildExceptionObject(e);
|
||||
excObject.logData = stringifyLogObjectFunction(logObject);
|
||||
}
|
||||
else {
|
||||
excObject = logObject;
|
||||
}
|
||||
compositeMessage = stringifyLogObject(excObject);
|
||||
if (allowMessage(this, compositeMessage.finalString)) {
|
||||
// See whether message is a duplicate
|
||||
if (this.onceOnly) {
|
||||
i = this.onceOnly.length - 1;
|
||||
while (i >= 0) {
|
||||
if (new RegExp(this.onceOnly[i]).test(compositeMessage.finalString)) {
|
||||
if (this.seenRegexes[i]) {
|
||||
return this;
|
||||
}
|
||||
this.seenRegexes[i] = true;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
// Pass message to all appenders
|
||||
// Note that these appenders could be Winston transports
|
||||
// https://github.com/flatiron/winston
|
||||
//
|
||||
// These transports do not take the logger name as a parameter.
|
||||
// So add it to the meta information, so even Winston transports will
|
||||
// store this info.
|
||||
compositeMessage.meta = compositeMessage.meta || {};
|
||||
compositeMessage.meta.loggerName = this.loggerName;
|
||||
i = this.appenders.length - 1;
|
||||
while (i >= 0) {
|
||||
this.appenders[i].log(levelToString(level), compositeMessage.msg, compositeMessage.meta, function () {
|
||||
}, level, compositeMessage.finalString, this.loggerName);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Logger.prototype.trace = function (logObject) {
|
||||
return this.log(getTraceLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.debug = function (logObject) {
|
||||
return this.log(getDebugLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.info = function (logObject) {
|
||||
return this.log(getInfoLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.warn = function (logObject) {
|
||||
return this.log(getWarnLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.error = function (logObject) {
|
||||
return this.log(getErrorLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.fatal = function (logObject) {
|
||||
return this.log(getFatalLevel(), logObject);
|
||||
};
|
||||
Logger.prototype.fatalException = function (logObject, e) {
|
||||
return this.log(getFatalLevel(), logObject, e);
|
||||
};
|
||||
return Logger;
|
||||
})();
|
||||
JL.Logger = Logger;
|
||||
function createAjaxAppender(appenderName) {
|
||||
return new AjaxAppender(appenderName);
|
||||
}
|
||||
JL.createAjaxAppender = createAjaxAppender;
|
||||
function createConsoleAppender(appenderName) {
|
||||
return new ConsoleAppender(appenderName);
|
||||
}
|
||||
JL.createConsoleAppender = createConsoleAppender;
|
||||
// -----------------------
|
||||
// In the browser, the default appender is the AjaxAppender.
|
||||
// Under nodejs (where there is no "window"), use the ConsoleAppender instead.
|
||||
var defaultAppender = new AjaxAppender("");
|
||||
if (typeof window === 'undefined') {
|
||||
defaultAppender = new ConsoleAppender("");
|
||||
}
|
||||
// Create root logger
|
||||
//
|
||||
// Note that this is the parent of all other loggers.
|
||||
// Logger "x" will be stored at
|
||||
// JL.__.x
|
||||
// Logger "x.y" at
|
||||
// JL.__.x.y
|
||||
JL.__ = new JL.Logger("");
|
||||
JL.__.setOptions({
|
||||
level: JL.getDebugLevel(),
|
||||
appenders: [defaultAppender]
|
||||
});
|
||||
})(JL || (JL = {}));
|
||||
// Support CommonJS module format
|
||||
var exports;
|
||||
if (typeof exports !== 'undefined') {
|
||||
exports.JL = JL;
|
||||
}
|
||||
// Support AMD module format
|
||||
var define;
|
||||
if (typeof define == 'function' && define.amd) {
|
||||
define('jsnlog', [], function () {
|
||||
return JL;
|
||||
});
|
||||
}
|
||||
// If the __jsnlog_configure global function has been
|
||||
// created, call it now. This allows you to create a global function
|
||||
// setting logger options etc. inline in the page before jsnlog.js
|
||||
// has been loaded.
|
||||
if (typeof __jsnlog_configure == 'function') {
|
||||
__jsnlog_configure(JL);
|
||||
}
|
||||
13
package.json
Normal file
13
package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "jsnlogProblem",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"author": "",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"grunt-browserify": "~3.8.0",
|
||||
"babelify": "~6.1.2",
|
||||
"grunt": "~0.4.5"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user