Skip to content

Commit 19ab286

Browse files
rluvatonjsumners
andauthored
allow passing callback to flush (#1827)
* allow passing callback to flush * Update api.md * Update docs/api.md Co-authored-by: James Sumners <321201+jsumners@users.noreply.github.com> * update sonic boom with the latest fix --------- Co-authored-by: James Sumners <321201+jsumners@users.noreply.github.com>
1 parent 7837851 commit 19ab286

File tree

7 files changed

+125
-11
lines changed

7 files changed

+125
-11
lines changed

docs/api.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -964,12 +964,12 @@ console.log(anotherChild.bindings())
964964
```
965965
966966
<a id="flush"></a>
967-
### `logger.flush()`
967+
### `logger.flush([cb])`
968968
969969
Flushes the content of the buffer when using `pino.destination({
970970
sync: false })`.
971971
972-
This is an asynchronous, fire and forget, operation.
972+
This is an asynchronous, best used as fire and forget, operation.
973973
974974
The use case is primarily for asynchronous logging, which may buffer
975975
log lines while others are being written. The `logger.flush` method can be
@@ -978,6 +978,8 @@ on a long interval, say ten seconds. Such a strategy can provide an
978978
optimum balance between extremely efficient logging at high demand periods
979979
and safer logging at low demand periods.
980980
981+
If there is a need to wait for the logs to be flushed, a callback should be used.
982+
981983
* See [`destination` parameter](#destination)
982984
* See [Asynchronous Logging ⇗](/docs/asynchronous.md)
983985

lib/proto.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,14 @@ function write (_obj, msg, num) {
219219

220220
function noop () {}
221221

222-
function flush () {
222+
function flush (cb) {
223+
if (cb != null && typeof cb !== 'function') {
224+
throw Error('callback must be a function')
225+
}
226+
223227
const stream = this[streamSym]
224-
if ('flush' in stream) stream.flush(noop)
228+
229+
if ('flush' in stream) {
230+
stream.flush(cb || noop)
231+
} else if (cb) cb()
225232
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"quick-format-unescaped": "^4.0.3",
111111
"real-require": "^0.2.0",
112112
"safe-stable-stringify": "^2.3.1",
113-
"sonic-boom": "^3.1.0",
113+
"sonic-boom": "^3.7.0",
114114
"thread-stream": "^2.0.0"
115115
},
116116
"tsd": {

pino.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ export interface LoggerExtras<Options = LoggerOptions> extends EventEmitter {
122122

123123
/**
124124
* Flushes the content of the buffer when using pino.destination({ sync: false }).
125+
* call the callback when finished
125126
*/
126-
flush(): void;
127+
flush(cb?: (err?: Error) => void): void;
127128
}
128129

129130

test/syncfalse.test.js

+73-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
'use strict'
22

33
const os = require('os')
4-
const { createWriteStream } = require('fs')
4+
const {
5+
createWriteStream
6+
} = require('fs')
7+
const { readFile } = require('fs').promises
58
const { join } = require('path')
69
const { test } = require('tap')
710
const { fork } = require('child_process')
811
const writer = require('flush-write-stream')
9-
const { once, getPathToNull } = require('./helper')
12+
const {
13+
once,
14+
getPathToNull,
15+
file,
16+
watchFileCreated
17+
} = require('./helper')
1018
const { promisify } = require('util')
1119

1220
const sleep = promisify(setTimeout)
1321

14-
test('asynchronous logging', async ({ equal, teardown }) => {
22+
test('asynchronous logging', async ({
23+
equal,
24+
teardown
25+
}) => {
1526
const now = Date.now
1627
const hostname = os.hostname
1728
const proc = process
@@ -63,7 +74,10 @@ test('asynchronous logging', async ({ equal, teardown }) => {
6374
})
6475
})
6576

66-
test('sync false with child', async ({ equal, teardown }) => {
77+
test('sync false with child', async ({
78+
equal,
79+
teardown
80+
}) => {
6781
const now = Date.now
6882
const hostname = os.hostname
6983
const proc = process
@@ -87,7 +101,9 @@ test('sync false with child', async ({ equal, teardown }) => {
87101
})).child({ hello: 'world' })
88102

89103
const dest = createWriteStream(getPathToNull())
90-
dest.write = function (s) { actual += s }
104+
dest.write = function (s) {
105+
actual += s
106+
}
91107
const asyncLogger = pino(dest).child({ hello: 'world' })
92108

93109
let i = 500
@@ -121,3 +137,55 @@ test('flush does nothing with sync true (default)', async ({ equal }) => {
121137
const instance = require('..')()
122138
equal(instance.flush(), undefined)
123139
})
140+
141+
test('should still call flush callback even when does nothing with sync true (default)', (t) => {
142+
t.plan(3)
143+
const instance = require('..')()
144+
instance.flush((...args) => {
145+
t.ok('flush called')
146+
t.same(args, [])
147+
148+
// next tick to make flush not called more than once
149+
process.nextTick(() => {
150+
t.ok('flush next tick called')
151+
})
152+
})
153+
})
154+
155+
test('should call the flush callback when flushed the data for async logger', async (t) => {
156+
const outputPath = file()
157+
async function getOutputLogLines () {
158+
return (await readFile(outputPath)).toString().trim().split('\n').map(JSON.parse)
159+
}
160+
161+
const pino = require('../')
162+
163+
const instance = pino({}, pino.destination({
164+
dest: outputPath,
165+
166+
// to make sure it does not flush on its own
167+
minLength: 4096
168+
}))
169+
const flushPromise = promisify(instance.flush).bind(instance)
170+
171+
instance.info('hello')
172+
await flushPromise()
173+
await watchFileCreated(outputPath)
174+
175+
const [firstFlushData] = await getOutputLogLines()
176+
177+
t.equal(firstFlushData.msg, 'hello')
178+
179+
// should not flush this as no data accumulated that's bigger than min length
180+
instance.info('world')
181+
182+
// Making sure data is not flushed yet
183+
const afterLogData = await getOutputLogLines()
184+
t.equal(afterLogData.length, 1)
185+
186+
await flushPromise()
187+
188+
// Making sure data is not flushed yet
189+
const afterSecondFlush = (await getOutputLogLines())[1]
190+
t.equal(afterSecondFlush.msg, 'world')
191+
})

test/transport/syncfalse.test.js

+35
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { join } = require('path')
66
const { test } = require('tap')
77
const { readFile } = require('fs').promises
88
const { watchFileCreated, file } = require('../helper')
9+
const { promisify } = require('util')
910

1011
const { pid } = process
1112
const hostname = os.hostname()
@@ -31,3 +32,37 @@ test('thread-stream async flush', async ({ equal, same }) => {
3132
msg: 'hello'
3233
})
3334
})
35+
36+
test('thread-stream async flush should call the passed callback', async (t) => {
37+
const outputPath = file()
38+
async function getOutputLogLines () {
39+
return (await readFile(outputPath)).toString().trim().split('\n').map(JSON.parse)
40+
}
41+
const transport = pino.transport({
42+
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
43+
options: { destination: outputPath }
44+
})
45+
const instance = pino(transport)
46+
const flushPromise = promisify(instance.flush).bind(instance)
47+
48+
instance.info('hello')
49+
await flushPromise()
50+
await watchFileCreated(outputPath)
51+
52+
const [firstFlushData] = await getOutputLogLines()
53+
54+
t.equal(firstFlushData.msg, 'hello')
55+
56+
// should not flush this as no data accumulated that's bigger than min length
57+
instance.info('world')
58+
59+
// Making sure data is not flushed yet
60+
const afterLogData = await getOutputLogLines()
61+
t.equal(afterLogData.length, 1)
62+
63+
await flushPromise()
64+
65+
// Making sure data is not flushed yet
66+
const afterSecondFlush = (await getOutputLogLines())[1]
67+
t.equal(afterSecondFlush.msg, 'world')
68+
})

test/types/pino.test-d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pino({ base: null });
112112
if ("pino" in log) console.log(`pino version: ${log.pino}`);
113113

114114
expectType<void>(log.flush());
115+
log.flush((err?: Error) => undefined);
115116
log.child({ a: "property" }).info("hello child!");
116117
log.level = "error";
117118
log.info("nope");

0 commit comments

Comments
 (0)