diff --git a/docs/layouts.md b/docs/layouts.md index e69de29..ca30e3a 100644 --- a/docs/layouts.md +++ b/docs/layouts.md @@ -0,0 +1,177 @@ +# Layouts + +Layouts are functions used by appenders to format log events for output. They take a log event as an argument and return a string. Log4js comes with several appenders built-in, and provides ways to create your own if these are not suitable. + +For most use cases you will not need to configure layouts - there are some appenders which do not need layouts defined (for example, [logFaces-UDP](logFaces-UDP.md)); all the appenders that use layouts will have a sensible default defined. + +## Configuration + +Most appender configuration will take a field called `layout`, which is an object - typically with a single field `type` which is the name of an appender defined below. Some appenders require extra configuration options, which should be included in the same object. + +## Example +```javascript +log4js.configure({ + appenders: { out: { type: 'stdout', layout: { type: 'basic' } } }, + categories: { default: { appenders: ['out'], level: 'info' } } +}); +``` +This configuration replaces the [stdout](stdout.md) appender's default `coloured` layout with `basic` layout. + +# Built-in Layouts + +## Basic + +* `type` - `basic` + +Basic layout will output the timestamp, level, category, followed by the formatted log event data. + +## Example +```javascript +log4js.configure({ + appenders: { 'out': { type: 'stdout', layout: { type: 'basic' } } }, + categories: { default: { appenders: ['out'], level: 'info' } } +}); +const logger = log4js.getLogger('cheese'); +logger.error('Cheese is too ripe!'); +``` +This will output: +``` +[2017-03-30 07:57:00.113] [ERROR] cheese - Cheese is too ripe! +``` + +## Coloured + +* `type` - `coloured` (or `colored`) + +This layout is the same as `basic`, except that the timestamp, level and category will be coloured according to the log event's level (if your terminal/file supports it - if you see some weird characters in your output and no colour then you should probably switch to `basic`). The colours used are: +* `TRACE` - 'blue' +* `DEBUG` - 'cyan' +* `INFO` - 'green' +* `WARN` - 'yellow' +* `ERROR` - 'red' +* `FATAL` - 'magenta' + +## Message Pass-Through +* `type` - `messagePassThrough` + +This layout just formats the log event data, and does not output a timestamp, level or category. It is typically used in appenders that serialise the events using a specific format (e.g. [gelf](gelf.md)). + +## Example +```javascript +log4js.configure({ + appenders: { out: { type: 'stdout', layout: { type: 'messagePassThrough' } } }, + categories: { default: { appenders: [ 'out' ], level: 'info' } } +}); +const logger = log4js.getLogger('cheese'); +const cheeseName = 'gouda'; +logger.error('Cheese is too ripe! Cheese was: ', cheeseName); +``` +This will output: +``` +Cheese is too ripe! Cheese was: gouda +``` + +## Dummy + +* `type` - `dummy` + +This layout only outputs the first value in the log event's data. It was added for the [logstashUDP](logstashUDP.md) appender, and I'm not sure there's much use for it outside that. + +## Example +```javascript +log4js.configure({ + appenders: { out: { type: 'stdout', layout: { type: 'dummy' } } }, + categories: { default: { appenders: [ 'out' ], level: 'info' } } +}); +const logger = log4js.getLogger('cheese'); +const cheeseName = 'gouda'; +logger.error('Cheese is too ripe! Cheese was: ', cheeseName); +``` +This will output: +``` +Cheese is too ripe! Cheese was: +``` + +## Pattern +* `type` - `pattern` +* `pattern` - `string` - specifier for the output format, using placeholders as described below +* `tokens` - `object` (optional) - user-defined tokens to be used in the pattern + +## Pattern format +The pattern string can contain any characters, but sequences beginning with `%` will be replaced with values taken from the log event, and other environmental values. +Format for specifiers is `%[padding].[truncation][field]{[format]}` - padding and truncation are optional, and format only applies to a few tokens (notably, date). +e.g. %5.10p - left pad the log level by 5 characters, up to a max of 10 + +Fields can be any of: +* `%r` time in toLocaleTimeString format +* `%p` log level +* `%c` log category +* `%h` hostname +* `%m` log data +* `%d` date, formatted - default is `ISO8601`, format options are: `ISO8601`, `ISO8601_WITH_TZ_OFFSET`, `ABSOLUTE`, `DATE`, or any string compatible with the [date-format](https://www.npmjs.com/package/date-format) library. e.g. `%d{DATE}`, `%d{yyyy/MM/dd-hh.mm.ss}` +* `%%` % - for when you want a literal `%` in your output +* `%n` newline +* `%z` process id (from `process.pid`) +* `%x{}` add dynamic tokens to your log. Tokens are specified in the tokens parameter. +* `%[` start a coloured block (colour will be taken from the log level, similar to `colouredLayout`) +* `%]` end a coloured block + +## Tokens +User-defined tokens can be either a string or a function. Functions will be passed the log event, and should return a string. For example, you could define a custom token that outputs the log event's context value for 'user' like so: +```javascript +log4js.configure({ + appenders: { + out: { type: 'stdout', layout: { + type: 'pattern', + pattern: '%d %p %c %x{user} %m%n', + tokens: { + user: function(logEvent) { + return logEvent.context.user; + } + } + }} + }, + categories: { default: { appenders: ['out'], level: 'info' } } +}); +const logger = log4js.getLogger(); +logger.addContext('user', 'charlie'); +logger.info('doing something.'); +``` +This would output: +``` +2017-06-01 08:32:56.283 INFO default charlie doing something. +``` + +# Adding your own layouts + +You can add your own layouts by calling `log4js.addLayout(type, fn)` before calling `log4js.configure`. `type` is the label you want to use to refer to your layout in appender configuration. `fn` is a function that takes a single object argument, which will contain the configuration for the layout instance, and returns a layout function. A layout function takes a log event argument and returns a string (usually, although you could return anything as long as the appender knows what to do with it). + +## Custom Layout Example (see examples/custom-layout.js) +```javascript +const log4js = require('log4js'); + +log4js.addLayout('json', function(config) { + return function(logEvent) { return JSON.stringify(logEvent) + config.separator; } +}); + +log4js.configure({ + appenders: { + out: { type: 'stdout', layout: { type: 'json', separator: ',' } } + }, + categories: { + default: { appenders: ['out'], level: 'info' } + } +}); + +const logger = log4js.getLogger('json-test'); +logger.info('this is just a test'); +logger.error('of a custom appender'); +logger.warn('that outputs json'); +log4js.shutdown(() => {}); +``` +This example outputs the following: +```javascript +{"startTime":"2017-06-05T22:23:08.479Z","categoryName":"json-test","data":["this is just a test"],"level":{"level":20000,"levelStr":"INFO"},"context":{}}, +{"startTime":"2017-06-05T22:23:08.483Z","categoryName":"json-test","data":["of a custom appender"],"level":{"level":40000,"levelStr":"ERROR"},"context":{}}, +{"startTime":"2017-06-05T22:23:08.483Z","categoryName":"json-test","data":["that outputs json"],"level":{"level":30000,"levelStr":"WARN"},"context":{}}, +``` diff --git a/examples/custom-layout.js b/examples/custom-layout.js new file mode 100644 index 0000000..8447c5a --- /dev/null +++ b/examples/custom-layout.js @@ -0,0 +1,20 @@ +const log4js = require('../lib/log4js'); + +log4js.addLayout('json', config => function (logEvent) { + return JSON.stringify(logEvent) + config.separator; +}); + +log4js.configure({ + appenders: { + out: { type: 'stdout', layout: { type: 'json', separator: ',' } } + }, + categories: { + default: { appenders: ['out'], level: 'info' } + } +}); + +const logger = log4js.getLogger('json-test'); +logger.info('this is just a test'); +logger.error('of a custom appender'); +logger.warn('that outputs json'); +log4js.shutdown(() => {}); diff --git a/lib/log4js.js b/lib/log4js.js index 8a682d5..88eeadc 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -27,6 +27,7 @@ const fs = require('fs'); const Configuration = require('./configuration'); const connectModule = require('./connect-logger'); const logger = require('./logger'); +const layouts = require('./layouts'); const defaultConfig = { appenders: { @@ -172,7 +173,8 @@ const log4js = { getLogger, configure, shutdown, - connectLogger + connectLogger, + addLayout: layouts.addLayout }; module.exports = log4js;