pino-syslog
Version:
A transport for pino that formats messages into syslog format
210 lines (159 loc) • 7.78 kB
Markdown
# pino-syslog
**Lead maintainer:** [jsumners](https://github.com/jsumners)
*pino-syslog* is a so called "transport" for the [pino][pino] logger. *pino-syslog* receives *pino* logs from `stdin`
and transforms them into [RFC3164][rfc3164] or [RFC5424][rfc5424] (syslog) formatted messages which are written to
`stdout`. The default output format is RFC5424.
This transport **does not** send messages to a remote, or even local, syslog compatible server. It merely reformats the
logs into syslog compatible strings. To send logs to a syslog server, use the [pino-socket][pino-socket] transport.
For example:
```bash
$ node your-app.js | pino-syslog | pino-socket -a syslog.example.com
```
[pino]: https://www.npmjs.com/package/pino
[rfc3164]: https://tools.ietf.org/html/rfc3164
[rfc5424]: https://tools.ietf.org/html/rfc5424
[pino-socket]: https://www.npmjs.com/package/pino-socket
## RFC3164
This RFC mandates that the maximum number of bytes that a syslog message may be
is `1024`. Thus, *pino-syslog* will do one of two things when this limit is exceeded:
1. Output a JSON error log, with syslog header, that includes the original log's `time` and `level` properties, a
`originalSize` property set to the number of bytes the original log message consumed, and a `msg` property set to
"message exceeded syslog 1024 byte limit".
2. Truncate the message to fit within the 1024 byte limit when the `messageOnly` configuration option is set to `true`.
This means you *can* lose data if your log messages are too large. If that is to be the case, you should investigate
the `includeProperties` option to reduce your log size. But, really, you should investigate what it is you are logging.
## RFC5424
This RFC does not limit the message size except to say that the ***receiver*** may impose a maximum. Thus, *pino-syslog*
does not impose a length limit when conforming to this RFC. There are a couple of things to note, though:
1. We do not currently support the structured data portion of the log header. This section of each log is always `-`.
2. If the data to be logged includes `req.id` then it will be used as the message id portion of the log. For example,
the data `{req: {id: '1234'}}` would have '1234' as the message id in the resulting formatted log.
These caveats may be configurable in a later version.
## Example
Given the log:
```json
{"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}
```
*pino-syslog* will write out:
```
<134>1 2016-04-01T16:44:58Z MacBook-Pro-3 - 94473 - - {"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}
```
Or, in RFC3164 mode:
```
<134>Apr 1 16:44:58 MacBook-Pro-3 none[94473]: {"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}
```
Putting it all together:
```bash
$ echo '{"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}' | node pino-syslog [s:0 l:8025]
<134>1 2016-04-01T16:44:58Z MacBook-Pro-3 - 94473 - - {"pid":94473,"hostname":"MacBook-Pro-3","level":30,"msg":"hello world","time":1459529098958,"v":1}
```
## Usage as Pino Transport
You can use this module as a [pino transport](https://getpino.io/#/docs/transports?id=v7-transports) like so:
```js
const pino = require('pino')
const transport = pino.transport({
target: 'pino-syslog',
level: 'info',
options: {
enablePipelining: false, // optional (default: true)
destination: 1, // optional (default: stdout)
... // other options
}
})
pino(transport)
```
The options object's properties are [described below](#configuration).
There is some extra properties:
+ `enablePipelining`: it must be set to `false` to disable the pino transport pipeline.
+ `destination`: it must be an integer which is used to specify the destination of the log messages. `1` is stdout, `2` is stderr and others numbers must be a file descriptor. This option is used only when the pipelining is disabled.
### Pipelining
This feature is enabled by default and let you to submit the `pino-syslog` output to another destination at your choice, such as a `socket` using the `pino-socket` module:
```js
const transport = pino.transport({
pipeline: [
{
target: 'pino-syslog',
level: 'info',
options: {
... // other options
}
},
{
target: 'pino-socket',
options: {
mode: 'tcp',
address: '127.0.0.1',
port: 8001
}
}
]
})
pino(transport)
```
## Usage as Pino Legacy Transport
Pino supports a [legacy transport interface](https://getpino.io/#/docs/transports?id=legacy-transports)
that is still supported by this module.
### Install
You should install *pino-syslog* globally so that it can be used as a utility:
```bash
$ npm install --production -g pino-syslog
```
## Configuration
*pino-syslog* supports configuration using option flags and/or via a JSON file. The option flags take precedence over the JSON configuration. The default options are:
```json
{
"modern": true,
"appname": "none",
"cee": false,
"facility": 16,
"includeProperties": [],
"messageOnly": false,
"tz": "UTC",
"newline": false,
"structuredData": "-",
"sync": false
}
```
This also shows the full structure of a configuration file, which can be loaded using `--config <path-to-file>` (`-c <path-to-file>`).
### Option flags
+ `--modern` (`-m`) (boolean): indicates if RFC5424 (`true`) or RFC3164 (`false`) should be used.
+ `--appname` (`-a`) (string): sets the name of the application in the 'TAG' portion of the syslog header.
+ `--cee` (boolean): denotes whether or not to prefix the message field with `: `. This will only work if
`messageOnly` is `false`.
+ `--facility` (`-f`) (number): a valid [facility number][facility], `[0 - 23]`.
+ `--includeProperties` (`-p`) (array<string>): a list of property names from the original *pino* log to include in the formatted
message. This is only applicable if `messageOnly` is `false`.
+ `--messageOnly` (`-mo`) (boolean): indicates if the message field should contain only the `msg` property of the *pino* log, or
if it should be stringified JSON.
+ `--tz` (string): any [valid timezone string][tzstring] that [luxon][luxon] will recognize. The timestamp field of the
syslog header will be sent according to this setting.
+ `--newline` (`-n`) (boolean): terminate with a newline
+ `--structuredData` (`-s`) (string): [structured data](https://tools.ietf.org/html/rfc5424#section-6.3) to send with an RFC5424 message.
+ `--sync` (`-sy`) (boolean): perform writes synchronously
[facility]: https://tools.ietf.org/html/rfc3164#section-4.1.1
[tzstring]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
[luxon]: https://moment.github.io/luxon/#/zones?id=specifying-a-zone
### Custom levels
Custom [Pino levels](https://github.com/pinojs/pino/blob/HEAD/docs/api.md#opt-customlevels) are supported.
They must be established through a mapping defined under the `customLevels`
configuration key. `customLevels` is a hash of hashes. Each key under
`customLevels` is a custom level name with a value that is a hash with
keys `level` and `syslogSeverity`. The `level` key maps to the log level number,
and the `syslogSeverity` key to the name of a spec compliant syslog level:
"emergency", "alert", "critical", "error", "warning", "notice", "info", or
"debug".
The following example shows how to add customized levels:
```json
{
"modern": true,
"appname": "none",
"customLevels": {
"customLevel_name": {
"level": 70,
"syslogSeverity": "alert"
}
}
}
```
## License
[MIT License](http://jsumners.mit-license.org/)