Comparing version 8.18.0 to 8.19.0
@@ -112,2 +112,3 @@ 'use strict' | ||
asObject: opts.browser.asObject, | ||
formatters: opts.browser.formatters, | ||
levels, | ||
@@ -303,4 +304,5 @@ timestamp: getTimeFunction(opts) | ||
} | ||
if (opts.asObject) write.call(proto, asObject(this, level, args, ts)) | ||
else write.apply(proto, args) | ||
if (opts.asObject || opts.formatters) { | ||
write.call(proto, asObject(this, level, args, ts, opts.formatters)) | ||
} else write.apply(proto, args) | ||
@@ -326,11 +328,16 @@ if (opts.transmit) { | ||
function asObject (logger, level, args, ts) { | ||
function asObject (logger, level, args, ts, formatters = {}) { | ||
const { | ||
level: levelFormatter = () => logger.levels.values[level], | ||
log: logObjectFormatter = (obj) => obj | ||
} = formatters | ||
if (logger._serialize) applySerializers(args, logger._serialize, logger.serializers, logger._stdErrSerialize) | ||
const argsCloned = args.slice() | ||
let msg = argsCloned[0] | ||
const o = {} | ||
const logObject = {} | ||
if (ts) { | ||
o.time = ts | ||
logObject.time = ts | ||
} | ||
o.level = logger.levels.values[level] | ||
logObject.level = levelFormatter(level, logger.levels.values[level]) | ||
let lvl = (logger._childLevel | 0) + 1 | ||
@@ -341,8 +348,10 @@ if (lvl < 1) lvl = 1 | ||
while (lvl-- && typeof argsCloned[0] === 'object') { | ||
Object.assign(o, argsCloned.shift()) | ||
Object.assign(logObject, argsCloned.shift()) | ||
} | ||
msg = argsCloned.length ? format(argsCloned.shift(), argsCloned) : undefined | ||
} else if (typeof msg === 'string') msg = format(argsCloned.shift(), argsCloned) | ||
if (msg !== undefined) o.msg = msg | ||
return o | ||
if (msg !== undefined) logObject.msg = msg | ||
const formattedLogObject = logObjectFormatter(logObject) | ||
return formattedLogObject | ||
} | ||
@@ -349,0 +358,0 @@ |
@@ -1265,3 +1265,3 @@ # API | ||
* `target`: The transport to pass logs through. This may be an installed module name or an absolute path. | ||
* `options`: An options object which is serialized (see [Structured Clone Algorithm][https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm]), passed to the worker thread, parsed and then passed to the exported transport function. | ||
* `options`: An options object which is serialized (see [Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)), passed to the worker thread, parsed and then passed to the exported transport function. | ||
* `worker`: [Worker thread](https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options) configuration options. Additionally, the `worker` option supports `worker.autoEnd`. If this is set to `false` logs will not be flushed on process exit. It is then up to the developer to call `transport.end()` to flush logs. | ||
@@ -1268,0 +1268,0 @@ * `targets`: May be specified instead of `target`. Must be an array of transport configurations. Transport configurations include the aforementioned `options` and `target` options plus a `level` option which will send only logs above a specified level to a transport. |
@@ -30,2 +30,21 @@ # Browser API | ||
### `formatters` (Object) | ||
An object containing functions for formatting the shape of the log lines. When provided, it enables the logger to produce a pino-like log object with customized formatting. Currently, it supports formatting for the `level` object only. | ||
##### `level` | ||
Changes the shape of the log level. The default shape is `{ level: number }`. | ||
The function takes two arguments, the label of the level (e.g. `'info'`) | ||
and the numeric value (e.g. `30`). | ||
```js | ||
const formatters = { | ||
level (label, number) { | ||
return { level: number } | ||
} | ||
} | ||
``` | ||
### `write` (Function | Object) | ||
@@ -32,0 +51,0 @@ |
@@ -424,2 +424,3 @@ # Transports | ||
+ [pino-opentelemetry-transport](#pino-opentelemetry-transport) | ||
+ [@axiomhq/pino](#@axiomhq/pino) | ||
@@ -1003,2 +1004,31 @@ ### Legacy | ||
<a id="@axiomhq/pino"></a> | ||
### @axiomhq/pino | ||
[@axiomhq/pino](https://www.npmjs.com/package/@axiomhq/pino) is the official [Axiom](https://axiom.co/) transport for Pino, using [axiom-js](https://github.com/axiomhq/axiom-js). | ||
```javascript | ||
import pino from 'pino'; | ||
const logger = pino( | ||
{ level: 'info' }, | ||
pino.transport({ | ||
target: '@axiomhq/pino', | ||
options: { | ||
dataset: process.env.AXIOM_DATASET, | ||
token: process.env.AXIOM_TOKEN, | ||
}, | ||
}), | ||
); | ||
``` | ||
then you can use the logger as usual: | ||
```js | ||
logger.info('Hello from pino!'); | ||
``` | ||
For further examples, head over to the [examples](https://github.com/axiomhq/axiom-js/tree/main/examples/pino) directory. | ||
<a id="communication-between-pino-and-transport"></a> | ||
@@ -1005,0 +1035,0 @@ ## Communication between Pino and Transports |
@@ -87,6 +87,7 @@ 'use strict' | ||
const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym] | ||
const levelComparison = this[levelCompSym] | ||
const hook = this[hooksSym].logMethod | ||
for (const key in values) { | ||
if (levelVal > values[key]) { | ||
if (levelComparison(values[key], levelVal) === false) { | ||
this[key] = noop | ||
@@ -93,0 +94,0 @@ continue |
'use strict' | ||
module.exports = { version: '8.18.0' } | ||
module.exports = { version: '8.19.0' } |
{ | ||
"name": "pino", | ||
"version": "8.18.0", | ||
"version": "8.19.0", | ||
"description": "super fast, all natural json logger", | ||
@@ -5,0 +5,0 @@ "main": "pino.js", |
@@ -169,2 +169,49 @@ 'use strict' | ||
test('opts.browser.formatters logs pino-like object to console', ({ end, ok, is }) => { | ||
const info = console.info | ||
console.info = function (o) { | ||
is(o.level, 30) | ||
is(o.label, 'info') | ||
is(o.msg, 'test') | ||
ok(o.time) | ||
console.info = info | ||
} | ||
const instance = require('../browser')({ | ||
browser: { | ||
formatters: { | ||
level (label, number) { | ||
return { label, level: number } | ||
} | ||
} | ||
} | ||
}) | ||
instance.info('test') | ||
end() | ||
}) | ||
test('opts.browser.formatters logs pino-like object to console', ({ end, ok, is }) => { | ||
const info = console.info | ||
console.info = function (o) { | ||
is(o.level, 30) | ||
is(o.msg, 'test') | ||
is(o.hello, 'world') | ||
is(o.newField, 'test') | ||
ok(o.time, `Logged at ${o.time}`) | ||
console.info = info | ||
} | ||
const instance = require('../browser')({ | ||
browser: { | ||
formatters: { | ||
log (o) { | ||
return { ...o, newField: 'test', time: `Logged at ${o.time}` } | ||
} | ||
} | ||
} | ||
}) | ||
instance.info({ hello: 'world' }, 'test') | ||
end() | ||
}) | ||
test('opts.browser.write func log single string', ({ end, ok, is }) => { | ||
@@ -171,0 +218,0 @@ const instance = pino({ |
@@ -530,2 +530,173 @@ 'use strict' | ||
test('changing level respects level comparison set to', async ({ test, end }) => { | ||
const ascLevels = { | ||
debug: 1, | ||
info: 2, | ||
warn: 3 | ||
} | ||
const descLevels = { | ||
debug: 3, | ||
info: 2, | ||
warn: 1 | ||
} | ||
const expected = { | ||
level: 2, | ||
msg: 'hello world' | ||
} | ||
test('ASC in parent logger', async ({ equal }) => { | ||
const customLevels = ascLevels | ||
const levelComparison = 'ASC' | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
test('DESC in parent logger', async ({ equal }) => { | ||
const customLevels = descLevels | ||
const levelComparison = 'DESC' | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
test('custom function in parent logger', async ({ equal }) => { | ||
const customLevels = { | ||
info: 2, | ||
debug: 345, | ||
warn: 789 | ||
} | ||
const levelComparison = (current, expected) => { | ||
if (expected === customLevels.warn) return false | ||
return true | ||
} | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
test('ASC in child logger', async ({ equal }) => { | ||
const customLevels = ascLevels | ||
const levelComparison = 'ASC' | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ }) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
test('DESC in parent logger', async ({ equal }) => { | ||
const customLevels = descLevels | ||
const levelComparison = 'DESC' | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ }) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
test('custom function in child logger', async ({ equal }) => { | ||
const customLevels = { | ||
info: 2, | ||
debug: 345, | ||
warn: 789 | ||
} | ||
const levelComparison = (current, expected) => { | ||
if (expected === customLevels.warn) return false | ||
return true | ||
} | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ }) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
end() | ||
}) | ||
test('changing level respects level comparison DESC', async ({ equal }) => { | ||
const customLevels = { | ||
warn: 1, | ||
info: 2, | ||
debug: 3 | ||
} | ||
const levelComparison = 'DESC' | ||
const expected = { | ||
level: 2, | ||
msg: 'hello world' | ||
} | ||
const stream = sink() | ||
const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream) | ||
logger.level = 'warn' | ||
logger.info('hello world') | ||
let result = stream.read() | ||
equal(result, null) | ||
logger.level = 'debug' | ||
logger.info('hello world') | ||
result = await once(stream, 'data') | ||
check(equal, result, expected.level, expected.msg) | ||
}) | ||
// testing for potential loss of Pino constructor scope from serializers - an edge case with circular refs see: https://github.com/pinojs/pino/issues/833 | ||
@@ -532,0 +703,0 @@ test('trying to get levels when `this` is no longer a Pino instance returns an empty string', async ({ equal }) => { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
705456
13919