Compare commits
21 Commits
logger-dec
...
v0.6.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd2ee14bde | ||
|
|
c09c11b147 | ||
|
|
b74a514369 | ||
|
|
73344ba79f | ||
|
|
22c156582f | ||
|
|
72bfb5d980 | ||
|
|
83ad0babf3 | ||
|
|
94034e1226 | ||
|
|
9b4c7d1574 | ||
|
|
770f2da627 | ||
|
|
eb51aa99be | ||
|
|
5286c50375 | ||
|
|
bb644a1632 | ||
|
|
a6efbf6273 | ||
|
|
2118d8f7b3 | ||
|
|
d2f044a451 | ||
|
|
d0661322aa | ||
|
|
8b8844694f | ||
|
|
abdba8e56f | ||
|
|
093f693232 | ||
|
|
b9bba00d8c |
@@ -12,6 +12,7 @@ Out of the box it supports the following features:
|
||||
* SMTP appender
|
||||
* GELF appender
|
||||
* hook.io appender
|
||||
* Loggly appender
|
||||
* multiprocess appender (useful when you've got worker processes)
|
||||
* a logger for connect/express servers
|
||||
* configurable log message layout/patterns
|
||||
|
||||
24
examples/loggly-appender.js
Normal file
24
examples/loggly-appender.js
Normal file
@@ -0,0 +1,24 @@
|
||||
//Note that loggly appender needs node-loggly to work.
|
||||
//If you haven't got node-loggly installed, you'll get cryptic
|
||||
//"cannot find module" errors when using the loggly appender
|
||||
var log4js = require('../lib/log4js');
|
||||
|
||||
log4js.configure({
|
||||
"appenders": [
|
||||
{
|
||||
type: "console",
|
||||
category: "test"
|
||||
},
|
||||
{
|
||||
"type" : "loggly",
|
||||
"token" : "12345678901234567890",
|
||||
"subdomain": "your-subdomain",
|
||||
"tags" : ["test"],
|
||||
"category" : "loggly"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var logger = log4js.getLogger("loggly");
|
||||
logger.info("Test log message");
|
||||
//logger.debug("Test log message");
|
||||
@@ -7,6 +7,14 @@ var log4js = require('../log4js');
|
||||
* Takes a loggingEvent object, returns string representation of it.
|
||||
*/
|
||||
function serializeLoggingEvent(loggingEvent) {
|
||||
// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
|
||||
// The following allows us to serialize errors correctly.
|
||||
for (var i = 0; i < loggingEvent.data.length; i++) {
|
||||
var item = loggingEvent.data[i];
|
||||
if (item && item.stack && JSON.stringify(item) === '{}') { // Validate that we really are in this case
|
||||
loggingEvent.data[i] = {stack : item.stack};
|
||||
}
|
||||
}
|
||||
return JSON.stringify(loggingEvent);
|
||||
}
|
||||
|
||||
@@ -115,4 +123,4 @@ function configure(config, options) {
|
||||
}
|
||||
|
||||
exports.appender = createAppender;
|
||||
exports.configure = configure;
|
||||
exports.configure = configure;
|
||||
|
||||
@@ -100,7 +100,7 @@ function gelfAppender (layout, host, port, hostname, facility) {
|
||||
msg.short_message = msg.full_message;
|
||||
|
||||
msg.version="1.0";
|
||||
msg.timestamp = msg.timestamp || new Date().getTime() / 1000 >> 0;
|
||||
msg.timestamp = msg.timestamp || new Date().getTime() / 1000; // log should use millisecond
|
||||
msg.host = hostname;
|
||||
msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
|
||||
msg.facility = facility;
|
||||
|
||||
37
lib/appenders/loggly.js
Normal file
37
lib/appenders/loggly.js
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
var layouts = require("../layouts")
|
||||
, loggly = require("loggly")
|
||||
, os = require('os');
|
||||
|
||||
/**
|
||||
* Loggly Appender. Sends logging events to Loggly using node-loggly
|
||||
*
|
||||
* @param config object with loggly configuration data
|
||||
* {
|
||||
* token: 'your-really-long-input-token',
|
||||
* subdomain: 'your-subdomain',
|
||||
* tags: ['loggly-tag1', 'loggly-tag2', .., 'loggly-tagn']
|
||||
* }
|
||||
* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
|
||||
*/
|
||||
function logglyAppender(config, layout) {
|
||||
layout = layout || layouts.basicLayout;
|
||||
|
||||
var client = loggly.createClient(config);
|
||||
|
||||
return function(loggingEvent) {
|
||||
client.log(layout(loggingEvent), config.tags);
|
||||
};
|
||||
}
|
||||
|
||||
function configure(config) {
|
||||
var layout;
|
||||
if (config.layout) {
|
||||
layout = layouts.layout(config.layout.type, config.layout);
|
||||
}
|
||||
return logglyAppender(config, layout);
|
||||
}
|
||||
|
||||
exports.name = "loggly";
|
||||
exports.appender = logglyAppender;
|
||||
exports.configure = configure;
|
||||
@@ -94,6 +94,11 @@ function workerAppender(config) {
|
||||
}
|
||||
|
||||
function write(loggingEvent) {
|
||||
// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
|
||||
// The following allows us to serialize errors correctly.
|
||||
if (loggingEvent && loggingEvent.stack && JSON.stringify(loggingEvent) === '{}') { // Validate that we really are in this case
|
||||
loggingEvent = {stack : loggingEvent.stack};
|
||||
}
|
||||
socket.write(JSON.stringify(loggingEvent), 'utf8');
|
||||
socket.write(END_MSG, 'utf8');
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ function format(str, req, res) {
|
||||
.replace(':referrer', req.headers.referer || req.headers.referrer || '')
|
||||
.replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor)
|
||||
.replace(
|
||||
':remote-addr',
|
||||
':remote-addr', req.ip || req._remoteAddress || (
|
||||
req.socket &&
|
||||
(req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))
|
||||
)
|
||||
))
|
||||
.replace(':user-agent', req.headers['user-agent'] || '')
|
||||
.replace(
|
||||
':content-length',
|
||||
|
||||
@@ -49,9 +49,12 @@ Logger.prototype.removeLevel = function() {
|
||||
|
||||
Logger.prototype.log = function() {
|
||||
var args = Array.prototype.slice.call(arguments)
|
||||
, logLevel = args.shift()
|
||||
, loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
|
||||
this.emit("log", loggingEvent);
|
||||
, logLevel = levels.toLevel(args.shift())
|
||||
, loggingEvent;
|
||||
if (this.isLevelEnabled(logLevel)) {
|
||||
loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
|
||||
this.emit("log", loggingEvent);
|
||||
}
|
||||
};
|
||||
|
||||
Logger.prototype.isLevelEnabled = function(otherLevel) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "log4js",
|
||||
"version": "0.6.8",
|
||||
"version": "0.6.11",
|
||||
"description": "Port of Log4js to work with node.",
|
||||
"keywords": [
|
||||
"logging",
|
||||
@@ -9,7 +9,7 @@
|
||||
"node"
|
||||
],
|
||||
"main": "./lib/log4js",
|
||||
"author": "Gareth Jones <gareth.jones@sensis.com.au>",
|
||||
"author": "Gareth Jones <gareth.nomiddlename@gmail.com>",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nomiddlename/log4js-node.git"
|
||||
|
||||
@@ -97,6 +97,7 @@ vows.describe('log4js cluster appender').addBatch({
|
||||
|
||||
// Actual test - log message using masterAppender
|
||||
workerAppender(new LoggingEvent('wovs', 'Info', ['workerAppender test']));
|
||||
workerAppender(new LoggingEvent('wovs', 'Info', [new Error('Error test')]));
|
||||
|
||||
var returnValue = {
|
||||
registeredProcessEvents: registeredProcessEvents,
|
||||
@@ -109,6 +110,14 @@ vows.describe('log4js cluster appender').addBatch({
|
||||
"worker appender should call process.send" : function(topic) {
|
||||
assert.equal(topic.registeredProcessEvents[0].type, '::log-message');
|
||||
assert.equal(JSON.parse(topic.registeredProcessEvents[0].event).data[0], "workerAppender test");
|
||||
},
|
||||
|
||||
"worker should serialize an Error correctly" : function(topic) {
|
||||
assert.equal(topic.registeredProcessEvents[1].type, '::log-message');
|
||||
assert(JSON.parse(topic.registeredProcessEvents[1].event).data[0].stack);
|
||||
var actual = JSON.parse(topic.registeredProcessEvents[1].event).data[0].stack;
|
||||
var expectedRegex = /^Error: Error test/;
|
||||
assert(actual.match(expectedRegex), "Expected: \n\n " + actual + "\n\n to match " + expectedRegex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
82
test/logglyAppender-test.js
Normal file
82
test/logglyAppender-test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, log4js = require('../lib/log4js')
|
||||
, sandbox = require('sandboxed-module')
|
||||
;
|
||||
|
||||
function setupLogging(category, options) {
|
||||
var msgs = [];
|
||||
|
||||
var fakeLoggly = {
|
||||
createClient: function (options) {
|
||||
return {
|
||||
config: options,
|
||||
log: function (msg, tags) {
|
||||
msgs.push({
|
||||
msg: msg,
|
||||
tags: tags
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var fakeLayouts = {
|
||||
layout: function(type, config) {
|
||||
this.type = type;
|
||||
this.config = config;
|
||||
return log4js.layouts.messagePassThroughLayout;
|
||||
},
|
||||
basicLayout: log4js.layouts.basicLayout,
|
||||
messagePassThroughLayout: log4js.layouts.messagePassThroughLayout
|
||||
};
|
||||
|
||||
var fakeConsole = {
|
||||
errors: [],
|
||||
error: function(msg, value) {
|
||||
this.errors.push({ msg: msg, value: value });
|
||||
}
|
||||
};
|
||||
|
||||
var logglyModule = sandbox.require('../lib/appenders/loggly', {
|
||||
requires: {
|
||||
'loggly': fakeLoggly,
|
||||
'../layouts': fakeLayouts
|
||||
},
|
||||
globals: {
|
||||
console: fakeConsole
|
||||
}
|
||||
});
|
||||
|
||||
log4js.addAppender(logglyModule.configure(options), category);
|
||||
|
||||
return {
|
||||
logger: log4js.getLogger(category),
|
||||
loggly: fakeLoggly,
|
||||
layouts: fakeLayouts,
|
||||
console: fakeConsole,
|
||||
results: msgs
|
||||
};
|
||||
}
|
||||
|
||||
log4js.clearAppenders();
|
||||
vows.describe('log4js logglyAppender').addBatch({
|
||||
'minimal config': {
|
||||
topic: function() {
|
||||
var setup = setupLogging('loggly', {
|
||||
token: 'your-really-long-input-token',
|
||||
subdomain: 'your-subdomain',
|
||||
tags: ['loggly-tag1', 'loggly-tag2', 'loggly-tagn']
|
||||
});
|
||||
|
||||
setup.logger.log('trace', 'Log event #1');
|
||||
return setup;
|
||||
},
|
||||
'there should be one message only': function (topic) {
|
||||
//console.log('topic', topic);
|
||||
assert.equal(topic.results.length, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}).export(module);
|
||||
@@ -75,6 +75,7 @@ vows.describe('Multiprocess Appender').addBatch({
|
||||
appender('after error, before connect');
|
||||
fakeNet.cbs.connect();
|
||||
appender('after error, after connect');
|
||||
appender(new Error('Error test'));
|
||||
|
||||
return fakeNet;
|
||||
},
|
||||
@@ -98,6 +99,13 @@ vows.describe('Multiprocess Appender').addBatch({
|
||||
assert.equal(net.data[6], JSON.stringify('after error, after connect'));
|
||||
assert.equal(net.data[7], '__LOG4JS__');
|
||||
assert.equal(net.createConnectionCalled, 2);
|
||||
},
|
||||
'should serialize an Error correctly': function(net) {
|
||||
assert(JSON.parse(net.data[8]).stack, "Expected:\n\n" + net.data[8] + "\n\n to have a 'stack' property");
|
||||
var actual = JSON.parse(net.data[8]).stack;
|
||||
var expectedRegex = /^Error: Error test/;
|
||||
assert(actual.match(expectedRegex), "Expected: \n\n " + actual + "\n\n to match " + expectedRegex);
|
||||
|
||||
}
|
||||
},
|
||||
'worker with timeout': {
|
||||
|
||||
Reference in New Issue
Block a user