You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
log4js-node/writing-appenders.md

4.1 KiB

Writing Appenders For log4js

Loading appenders

log4js supports loading appender modules from outside its own code. The log4js-gelf, log4js-smtp, and log4js-hookio appenders are examples of this. In the configuration for an appender, log4js will first attempt to require the module from ./lib/appenders/ + type within log4js - if that fails, it will require just using the type. e.g.

log4js.configure({
	appenders: {
		"custom": { type: "log4js-gelf", hostname: "blah", port: 1234 }
	},
	categories: {
		"default": { level: "debug", appenders: ["custom"] }
	}
});

log4js will first attempt to require('./appenders/' + log4js-gelf), this will fail. It will then attempt require('log4js-gelf'), which (assuming you have previously run npm install log4js-gelf) will pick up the gelf appender.

Writing your own custom appender

This is easiest to explain with an example. Let's assume you want to write a CouchDB appender. CouchDB is a document database that you talk to via HTTP and JSON. Our log4js configuration is going to look something like this:

log4js.configure({
	appenders: {
		"couch": { 
			type: "log4js-couchdb", 
			url: "http://mycouchhost:5984", 
			db: "logs",
			layout: {
				type: "messagePassThrough"
			}
		}
	},
	categories: {
		"default": { level: "debug", appenders: ["couch"] }
	}
});

When processing this configuration, the first thing log4js will do is require('log4js-couchdb'). It expects this module to return a function that accepts two arguments

module.exports = function(layouts, levels) {
...	
};

log4js will then call that function, passing in the layouts and levels sub-modules in case your appender might need to use them. Layouts contains functions which will format a log event as a string in various different ways. Levels contains the definitions of the log levels used by log4js - you might need this for mapping log4js levels to external definitions (the GELF appender does this). These are passed in so that appenders do not need to include a hard dependency on log4js (see below), and so that log4js does not need to expose these modules to the public API. The module function will only be called once per call to log4js.configure, even if there are multiple appenders of that type defined.

The module function should return another function, a configuration function, which will be called for each appender of that type defined in the config. That function should return an appender instance. For our CouchDB example, the calling process is roughly like this:

couchDbModule = require('log4js-couchdb');
appenderMaker = couchDbModule(layouts, levels);
appender = appenderMaker({
	type: "log4js-couchdb",
	url: "http://mycouchhost:5984",
	db: "logs",
	layout: {
		type: "messagePassThrough"
	}
}, appenderByName)

Note that in addition to our couchdb appender config, the appenderMaker function gets an extra argument: appenderByName, a function which returns an appender when passed its name. This is used by appenders that wrap other appenders. The logLevelFilter is an example of this use.

The layout portion of the config can be passed directly to layouts.layout(config.layout) to generate a layout function.

The appender function returned after processing your config should just take one argument: a log event. This function will be called for every log event that should be handled by your appender. In our case, with the config above, every log event of DEBUG level and above will be sent to our appender.

Dependencies

You should declare which version of log4js your appender works with by including a "peerDependencies" section in your package.json. e.g.

{
    "name": "my-cool-appender",
    "version": "0.0.1",
    ...
    "peerDependencies": {
        "log4js": "0.7.x"
    }
}

For more details on peer dependencies, see this blog post.