1 | # Asynchronous Logging
|
2 |
|
3 | In essence, asynchronous logging enables even faster performance by Pino.
|
4 |
|
5 | In Pino's standard mode of operation log messages are directly written to the
|
6 | output stream as the messages are generated with a _blocking_ operation.
|
7 | Asynchronous logging works by buffering
|
8 | log messages and writing them in larger chunks.
|
9 |
|
10 | ## Caveats
|
11 |
|
12 | This has a couple of important caveats:
|
13 |
|
14 | * 4KB of spare RAM will be needed for logging
|
15 | * As opposed to the default mode, there is not a one-to-one relationship between
|
16 | calls to logging methods (e.g. `logger.info`) and writes to a log file
|
17 | * There is a possibility of the most recently buffered log messages being lost
|
18 | (up to 4KB of logs)
|
19 | * For instance, a power cut will mean up to 4KB of buffered logs will be lost
|
20 |
|
21 | So in summary, only use extreme mode when performing an extreme amount of
|
22 | logging and it is acceptable to potentially lose the most recent logs.
|
23 |
|
24 | * Pino will register handlers for the following process events/signals so that
|
25 | Pino can flush the extreme mode buffer:
|
26 |
|
27 | + `beforeExit`
|
28 | + `exit`
|
29 | + `uncaughtException`
|
30 | + `SIGHUP`
|
31 | + `SIGINT`
|
32 | + `SIGQUIT`
|
33 | + `SIGTERM`
|
34 |
|
35 | In all of these cases, except `SIGHUP`, the process is in a state that it
|
36 | *must* terminate. Thus, if an `onTerminated` function isn't registered when
|
37 | constructing a Pino instance (see [pino#constructor](api.md#constructor)),
|
38 | then Pino will invoke `process.exit(0)` when no error has occurred, or
|
39 | `process.exit(1)` otherwise. If an `onTerminated` function is supplied, it
|
40 | is the responsibility of the `onTerminated` function to manually exit the process.
|
41 |
|
42 | In the case of `SIGHUP`, we will look to see if any other handlers are
|
43 | registered for the event. If not, we will proceed as we do with all other
|
44 | signals. If there are more handlers registered than just our own, we will
|
45 | simply flush the asynchronous logging buffer.
|
46 |
|
47 | ### AWS Lambda
|
48 |
|
49 | On AWS Lambda we recommend to call `dest.flushSync()` at the end
|
50 | of each function execution to avoid losing data.
|
51 |
|
52 | ## Usage
|
53 |
|
54 | The `pino.destination({ sync: false })` method will provide an asynchronous destination.
|
55 |
|
56 | ```js
|
57 | const pino = require('pino')
|
58 | const dest = pino.destination({ sync: false }) // logs to stdout with no args
|
59 | const logger = pino(dest)
|
60 | ```
|
61 |
|
62 | <a id='log-loss-prevention'></a>
|
63 | ## Log loss prevention
|
64 |
|
65 | The following strategy can be used to minimize log loss:
|
66 |
|
67 | ```js
|
68 | const pino = require('pino')
|
69 | const dest = pino.destination({ sync: false })
|
70 | const logger = pino(dest)
|
71 |
|
72 | // asynchronously flush every 10 seconds to keep the buffer empty
|
73 | // in periods of low activity
|
74 | setInterval(function () {
|
75 | logger.flush()
|
76 | }, 10000).unref()
|
77 |
|
78 | // use pino.final to create a special logger that
|
79 | // guarantees final tick writes
|
80 | const handler = pino.final(logger, (err, finalLogger, evt) => {
|
81 | finalLogger.info(`${evt} caught`)
|
82 | if (err) finalLogger.error(err, 'error caused exit')
|
83 | process.exit(err ? 1 : 0)
|
84 | })
|
85 | // catch all the ways node might exit
|
86 | process.on('beforeExit', () => handler(null, 'beforeExit'))
|
87 | process.on('exit', () => handler(null, 'exit'))
|
88 | process.on('uncaughtException', (err) => handler(err, 'uncaughtException'))
|
89 | process.on('SIGINT', () => handler(null, 'SIGINT'))
|
90 | process.on('SIGQUIT', () => handler(null, 'SIGQUIT'))
|
91 | process.on('SIGTERM', () => handler(null, 'SIGTERM'))
|
92 | ```
|
93 |
|
94 | An extreme destination is an instance of
|
95 | [`SonicBoom`](https://github.com/mcollina/sonic-boom) with `4096`
|
96 | buffering.
|
97 |
|
98 |
|
99 | * See [`pino.destination` api](/docs/api.md#pino-destination)
|
100 | * See [`pino.final` api](/docs/api.md#pino-final)
|
101 | * See [`destination` parameter](/docs/api.md#destination)
|