Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pino

Package Overview
Dependencies
Maintainers
4
Versions
311
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pino - npm Package Compare versions

Comparing version 8.8.0 to 8.16.2

.eslintignore

187

browser.js

@@ -16,5 +16,38 @@ 'use strict'

res: mock,
err: asErrValue
err: asErrValue,
errWithCause: asErrValue
}
function levelToValue (level, logger) {
return level === 'silent'
? Infinity
: logger.levels.values[level]
}
const baseLogFunctionSymbol = Symbol('pino.logFuncs')
const hierarchySymbol = Symbol('pino.hierarchy')
const logFallbackMap = {
error: 'log',
fatal: 'error',
warn: 'error',
info: 'log',
debug: 'log',
trace: 'log'
}
function appendChildLogger (parentLogger, childLogger) {
const newEntry = {
logger: childLogger,
parent: parentLogger[hierarchySymbol]
}
childLogger[hierarchySymbol] = newEntry
}
function setupBaseLogFunctions (logger, levels, proto) {
const logFunctions = {}
levels.forEach(level => {
logFunctions[level] = proto[level] ? proto[level] : (_console[level] || _console[logFallbackMap[level] || 'log'] || noop)
})
logger[baseLogFunctionSymbol] = logFunctions
}
function shouldSerialize (serialize, serializers) {

@@ -51,7 +84,9 @@ if (Array.isArray(serialize)) {

const levels = ['error', 'fatal', 'warn', 'info', 'debug', 'trace']
const customLevels = Object.keys(opts.customLevels || {})
const levels = ['error', 'fatal', 'warn', 'info', 'debug', 'trace'].concat(customLevels)
if (typeof proto === 'function') {
proto.error = proto.fatal = proto.warn =
proto.info = proto.debug = proto.trace = proto
levels.forEach(function (level) {
proto[level] = proto
})
}

@@ -63,2 +98,6 @@ if (opts.enabled === false || opts.browser.disabled) opts.level = 'silent'

setupBaseLogFunctions(logger, levels, proto)
// setup root hierarchy entry
appendChildLogger({}, logger)
Object.defineProperty(logger, 'levelVal', {

@@ -79,3 +118,3 @@ get: getLevelVal

}
logger.levels = pino.levels
logger.levels = getLevels(opts)
logger.level = level

@@ -98,5 +137,3 @@

function getLevelVal () {
return this.level === 'silent'
? Infinity
: this.levels.values[this.level]
return levelToValue(this.level, this)
}

@@ -113,8 +150,12 @@

set(setOpts, logger, 'error', 'log') // <-- must stay first
set(setOpts, logger, 'fatal', 'error')
set(setOpts, logger, 'warn', 'error')
set(setOpts, logger, 'info', 'log')
set(setOpts, logger, 'debug', 'log')
set(setOpts, logger, 'trace', 'log')
set(this, setOpts, logger, 'error') // <-- must stay first
set(this, setOpts, logger, 'fatal')
set(this, setOpts, logger, 'warn')
set(this, setOpts, logger, 'info')
set(this, setOpts, logger, 'debug')
set(this, setOpts, logger, 'trace')
customLevels.forEach((level) => {
set(this, setOpts, logger, level)
})
}

@@ -141,8 +182,6 @@

this._childLevel = (parent._childLevel | 0) + 1
this.error = bind(parent, bindings, 'error')
this.fatal = bind(parent, bindings, 'fatal')
this.warn = bind(parent, bindings, 'warn')
this.info = bind(parent, bindings, 'info')
this.debug = bind(parent, bindings, 'debug')
this.trace = bind(parent, bindings, 'trace')
// make sure bindings are available in the `set` function
this.bindings = bindings
if (childSerializers) {

@@ -159,3 +198,10 @@ this.serializers = childSerializers

Child.prototype = this
return new Child(this)
const newLogger = new Child(this)
// must happen before the level is assigned
appendChildLogger(this, newLogger)
// required to actually initialize the logger functions for any given child
newLogger.level = this.level
return newLogger
}

@@ -165,2 +211,22 @@ return logger

function getLevels (opts) {
const customLevels = opts.customLevels || {}
const values = Object.assign({}, pino.levels.values, customLevels)
const labels = Object.assign({}, pino.levels.labels, invertObject(customLevels))
return {
values,
labels
}
}
function invertObject (obj) {
const inverted = {}
Object.keys(obj).forEach(function (key) {
inverted[obj[key]] = key
})
return inverted
}
pino.levels = {

@@ -188,15 +254,50 @@ values: {

function set (opts, logger, level, fallback) {
const proto = Object.getPrototypeOf(logger)
logger[level] = logger.levelVal > logger.levels.values[level]
function getBindingChain (logger) {
const bindings = []
if (logger.bindings) {
bindings.push(logger.bindings)
}
// traverse up the tree to get all bindings
let hierarchy = logger[hierarchySymbol]
while (hierarchy.parent) {
hierarchy = hierarchy.parent
if (hierarchy.logger.bindings) {
bindings.push(hierarchy.logger.bindings)
}
}
return bindings.reverse()
}
function set (self, opts, rootLogger, level) {
// override the current log functions with either `noop` or the base log function
self[level] = levelToValue(self.level, rootLogger) > levelToValue(level, rootLogger)
? noop
: (proto[level] ? proto[level] : (_console[level] || _console[fallback] || noop))
: rootLogger[baseLogFunctionSymbol][level]
wrap(opts, logger, level)
if (!opts.transmit && self[level] === noop) {
return
}
// make sure the log format is correct
self[level] = createWrap(self, opts, rootLogger, level)
// prepend bindings if it is not the root logger
const bindings = getBindingChain(self)
if (bindings.length === 0) {
// early exit in case for rootLogger
return
}
self[level] = prependBindingsInArguments(bindings, self[level])
}
function wrap (opts, logger, level) {
if (!opts.transmit && logger[level] === noop) return
function prependBindingsInArguments (bindings, logFunc) {
return function () {
return logFunc.apply(this, [...bindings, ...arguments])
}
}
logger[level] = (function (write) {
function createWrap (self, opts, rootLogger, level) {
return (function (write) {
return function LOG () {

@@ -215,5 +316,5 @@ const ts = opts.timestamp()

if (opts.transmit) {
const transmitLevel = opts.transmit.level || logger.level
const transmitValue = pino.levels.values[transmitLevel]
const methodValue = pino.levels.values[level]
const transmitLevel = opts.transmit.level || self._level
const transmitValue = rootLogger.levels.values[transmitLevel]
const methodValue = rootLogger.levels.values[level]
if (methodValue < transmitValue) return

@@ -225,9 +326,9 @@ transmit(this, {

transmitLevel,
transmitValue: pino.levels.values[opts.transmit.level || logger.level],
transmitValue: rootLogger.levels.values[opts.transmit.level || self._level],
send: opts.transmit.send,
val: logger.levelVal
val: levelToValue(self._level, rootLogger)
}, args)
}
}
})(logger[level])
})(self[baseLogFunctionSymbol][level])
}

@@ -243,3 +344,3 @@

}
o.level = pino.levels.values[level]
o.level = logger.levels.values[level]
let lvl = (logger._childLevel | 0) + 1

@@ -272,13 +373,2 @@ if (lvl < 1) lvl = 1

function bind (parent, bindings, level) {
return function () {
const args = new Array(1 + arguments.length)
args[0] = bindings
for (var i = 1; i < args.length; i++) {
args[i] = arguments[i - 1]
}
return parent[level].apply(this, args)
}
}
function transmit (logger, opts, args) {

@@ -373,1 +463,4 @@ const send = opts.send

/* eslint-enable */
module.exports.default = pino
module.exports.pino = pino

@@ -61,3 +61,3 @@ # API

One of `'fatal'`, `'error'`, `'warn'`, `'info`', `'debug'`, `'trace'` or `'silent'`.
One of `'fatal'`, `'error'`, `'warn'`, `'info'`, `'debug'`, `'trace'` or `'silent'`.

@@ -125,2 +125,4 @@ Additional levels can be added to the instance via the `customLevels` option.

logging methods is called. The first parameter is the value `mergeObject` or an empty object. The second parameter is the log level number.
The third parameter is the logger or child logger itself, which can be used to
retrieve logger-specific context from within the `mixin` function.
The function must synchronously return an object. The properties of the returned object will be added to the

@@ -176,10 +178,43 @@ logged JSON.

}, 'Message 1')
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","description":"Ok","level-label":"info","msg":"Message 1"}
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","description":"Ok","level-label":"info","msg":"Message 1"}
logger.error('Message 2')
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","description":"Ok","level-label":"error","msg":"Message 2"}
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","level-label":"error","msg":"Message 2"}
```
If the `mixin` feature is being used merely to add static metadata to each log message,
then a [child logger ⇗](/docs/child-loggers.md) should be used instead.
then a [child logger ⇗](/docs/child-loggers.md) should be used instead. Unless your application
needs to concatenate values for a specific key multiple times, in which case `mixin` can be
used to avoid the [duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat):
```js
const logger = pino({
mixin (obj, num, logger) {
return {
tags: logger.tags
}
}
})
logger.tags = {}
logger.addTag = function (key, value) {
logger.tags[key] = value
}
function createChild (parent, ...context) {
const newChild = logger.child(...context)
newChild.tags = { ...logger.tags }
newChild.addTag = function (key, value) {
newChild.tags[key] = value
}
return newChild
}
logger.addTag('foo', 1)
const child = createChild(logger, {})
child.addTag('bar', 2)
logger.info('this will only have `foo: 1`')
child.info('this will have both `foo: 1` and `bar: 2`')
logger.info('this will still only have `foo: 1`')
```
As of pino 7.x, when the `mixin` is used with the [`nestedKey` option](#opt-nestedkey),

@@ -347,4 +382,4 @@ the object returned from the `mixin` method will also be nested. Prior versions would mix

Changes the shape of the bindings. The default shape is `{ pid, hostname }`.
The function takes a single argument, the bindings object. It will
be called every time a child logger is created.
The function takes a single argument, the bindings object, which can be configured
using the [`base` option](#opt-base). Called once when creating logger.

@@ -391,2 +426,21 @@ ```js

#### `msgPrefix` (String)
Default: `undefined`
The `msgPrefix` property allows you to specify a prefix for every message of the logger and its children.
```js
const logger = pino({
msgPrefix: '[HTTP] '
})
logger.info('got new request!')
// > [HTTP] got new request!
const child = logger.child({})
child.info('User authenticated!')
// > [HTTP] User authenticated!
```
<a id=opt-base></a>
#### `base` (Object)

@@ -850,2 +904,22 @@

##### `options.msgPrefix` (String)
Default: `undefined`
The `msgPrefix` property allows you to specify a prefix for every message of the child logger.
By default, the parent prefix is inherited.
If the parent already has a prefix, the prefix of the parent and then the child will be displayed.
```js
const logger = pino({
msgPrefix: '[HTTP] '
})
logger.info('got new request!')
// > [HTTP] got new request!
const child = logger.child({avengers: 'assemble'}, {msgPrefix: '[Proxy] '})
child.info('message proxied!')
// > [HTTP] [Proxy] message proxied!
```
##### `options.redact` (Array | Object)

@@ -899,3 +973,3 @@

<a id="flush"></a>
### `logger.flush()`
### `logger.flush([cb])`

@@ -905,3 +979,3 @@ Flushes the content of the buffer when using `pino.destination({

This is an asynchronous, fire and forget, operation.
This is an asynchronous, best used as fire and forget, operation.

@@ -915,2 +989,4 @@ The use case is primarily for asynchronous logging, which may buffer

If there is a need to wait for the logs to be flushed, a callback should be used.
* See [`destination` parameter](#destination)

@@ -1174,2 +1250,3 @@ * See [Asynchronous Logging ⇗](/docs/asynchronous.md)

* `pipeline`: May be specified instead of `target`. Must be an array of transport configurations. Transport configurations include the aforementioned `options` and `target` options. All intermediate steps in the pipeline _must_ be `Transform` streams and not `Writable`.
* `dedupe`: See [pino.multistream options](#pino-multistream)

@@ -1204,3 +1281,3 @@ <a id="pino-multistream"></a>

In order for `multistream` to work, the log level __must__ be set to the lowest level used in the streams array.
In order for `multistream` to work, the log level __must__ be set to the lowest level used in the streams array. Default is `info`.

@@ -1219,3 +1296,3 @@ #### Options

var streams = [
{stream: process.stdout},
{level: 'debug', stream: process.stdout},
{level: 'error', stream: process.stderr},

@@ -1222,0 +1299,0 @@ ]

@@ -77,1 +77,2 @@ # Pino Ecosystem

+ [`cloud-pine`](https://github.com/metcoder95/cloud-pine): transport that provides abstraction and compatibility with [`@google-cloud/logging`](https://www.npmjs.com/package/@google-cloud/logging).
+ [`crawlee-pino`](https://github.com/imyelo/crawlee-pino): use Pino to log within Crawlee

@@ -15,2 +15,3 @@ # Help

* [Avoid Message Conflict](#avoid-message-conflict)
* [Best performance for logging to `stdout`](#best-performance-for-stdout)

@@ -292,1 +293,14 @@ <a id="rotate"></a>

```
<a id="best-performance-for-stdout"></a>
## Best performance for logging to `stdout`
The best performance for logging directly to stdout is _usually_ achieved by using the
default configuration:
```js
const log = require('pino')();
```
You should only have to configure custom transports or other settings
if you have broader logging requirements.

@@ -8,67 +8,29 @@ # Pretty Printing

```sh
$ cat app.log | pino-pretty
```
For almost all situations, this is the recommended way to prettify logs. The
programmatic API, described in the next section, is primarily for integration
purposes with other CLI-based prettifiers.
## Prettifier API
Pino prettifier modules are extra modules that provide a CLI for parsing NDJSON
log lines piped via `stdin` and expose an API that conforms to the Pino
[metadata streams](/docs/api.md#metadata) API.
The API requires modules provide a factory function that returns a prettifier
function. This prettifier function must accept either a string of NDJSON or
a Pino log object. A pseudo-example of such a prettifier is:
The uninitialized Pino instance is passed as `this` into prettifier factory function,
so it can be accessed via closure by the returned prettifier function.
```js
module.exports = function myPrettifier (options) {
// `this` is bound to the pino instance
// Deal with whatever options are supplied.
return function prettifier (inputData) {
let logObject
if (typeof inputData === 'string') {
logObject = someJsonParser(inputData)
} else if (isObject(inputData)) {
logObject = inputData
}
if (!logObject) return inputData
// implement prettification
}
function isObject (input) {
return Object.prototype.toString.apply(input) === '[object Object]'
}
}
```
The reference implementation of such a module is the [`pino-pretty`][pp] module.
To learn more about creating a custom prettifier module, refer to the
`pino-pretty` source code.
Note: if the prettifier returns `undefined`, instead of a formatted line, nothing
will be written to the destination stream.
### API Example
> #### NOTE:
> For general usage, it is highly recommended that logs are piped into
> the prettifier instead. Prettified logs are not easily parsed and cannot
> be easily investigated at a later date.
1. Install a prettifier module as a separate dependency, e.g. `npm install pino-pretty`.
1. Instantiate the logger with the prettifier option:
2. Instantiate the logger with the `transport.target` option set to `'pino-pretty'`:
```js
const pino = require('pino')
const log = pino({
prettifier: require('pino-pretty')
const logger = pino({
transport: {
target: 'pino-pretty'
},
})
logger.info('hi')
```
3. The transport option can also have an options object containing `pino-pretty` options:
```js
const pino = require('pino')
const logger = pino({
transport: {
target: 'pino-pretty',
options: {
colorize: true
}
}
})
logger.info('hi')
```
[pp]: https://github.com/pinojs/pino-pretty

@@ -18,2 +18,4 @@ # Transports

and can be used or configured via the options object passed to `pino` on initialization.
In this case the transports would always operate asynchronously, and logs would be
flushed as quickly as possible (there is nothing to do).

@@ -113,2 +115,15 @@ [worker-thread]: https://nodejs.org/dist/latest-v14.x/docs/api/worker_threads.html

It is also possible to use the `dedupe` option to send logs only to the stream with the higher level.
```js
const pino = require('pino')
const transport = pino.transport({
targets: [
{ target: '/absolute/path/to/my-transport.mjs', level: 'error' },
{ target: 'some-file-transport', options: { destination: '/dev/null' }
],
dedupe: true
})
pino(transport)
```
For more details on `pino.transport` see the [API docs for `pino.transport`][pino-transport].

@@ -140,3 +155,3 @@

for await (let obj of source) {
const toDrain = !destination.write(obj.message.toUpperCase() + '\n')
const toDrain = !destination.write(obj.msg.toUpperCase() + '\n')
// This block will handle backpressure

@@ -328,3 +343,3 @@ if (toDrain) {

{ target: '/absolute/path/to/my-transport.mjs', level: 'error' },
{ target: 'some-file-transport', options: { destination: '/dev/null' }
{ target: 'some-file-transport', options: { destination: '/dev/null' } }
]

@@ -382,2 +397,3 @@ })

+ [@logtail/pino](#@logtail/pino)
+ [pino-elasticsearch](#pino-elasticsearch)

@@ -390,2 +406,5 @@ + [pino-pretty](#pino-pretty)

+ [pino-datadog-transport](#pino-datadog-transport)
+ [pino-slack-webhook](#pino-slack-webhook)
+ [pino-axiom](#pino-axiom)
+ [pino-opentelemetry-transport](#pino-opentelemetry-transport)

@@ -418,3 +437,9 @@ ### Legacy

<a id="@logtail/pino"></a>
### @logtail/pino
The [@logtail/pino](https://www.npmjs.com/package/@logtail/pino) NPM package is a transport that forwards logs to [Logtail](https://logtail.com) by [Better Stack](https://betterstack.com).
[Quick start guide ⇗](https://betterstack.com/docs/logs/javascript/pino)
<a id="pino-applicationinsights"></a>

@@ -896,4 +921,70 @@ ### pino-applicationinsights

<a id="pino-slack-webhook"></a>
### pino-slack-webhook
[pino-slack-webhook][pino-slack-webhook] is a Pino v7+ compatible transport to forward log events to [Slack][Slack]
from a dedicated worker:
```js
const pino = require('pino')
const transport = pino.transport({
target: '@youngkiu/pino-slack-webhook',
options: {
webhookUrl: 'https://hooks.slack.com/services/xxx/xxx/xxx',
channel: '#pino-log',
username: 'webhookbot',
icon_emoji: ':ghost:'
}
})
pino(transport)
```
[pino-slack-webhook]: https://github.com/youngkiu/pino-slack-webhook
[Slack]: https://slack.com/
[pino-pretty]: https://github.com/pinojs/pino-pretty
For full documentation of command line switches read the [README](https://github.com/abeai/pino-websocket#readme).
<a id="pino-axiom"></a>
### pino-axiom
[pino-axiom](https://www.npmjs.com/package/pino-axiom) is a transport that will forward logs to [Axiom](https://axiom.co).
```javascript
const pino = require('pino')
const transport = pino.transport({
target: 'pino-axiom',
options: {
orgId: 'YOUR-ORG-ID',
token: 'YOUR-TOKEN',
dataset: 'YOUR-DATASET',
},
})
pino(transport)
```
<a id="pino-opentelemetry-transport"></a>
### pino-opentelemetry-transport
[pino-opentelemetry-transport](https://www.npmjs.com/package/pino-opentelemetry-transport) is a transport that will forward logs to an [OpenTelemetry log collector](https://opentelemetry.io/docs/collector/) using [OpenTelemetry JS instrumentation](https://opentelemetry.io/docs/instrumentation/js/).
```javascript
const pino = require('pino')
const transport = pino.transport({
target: 'pino-opentelemetry-transport',
options: {
resourceAttributes: {
'service.name': 'test-service',
'service.version': '1.0.0'
}
}
})
pino(transport)
```
Documentation on running a minimal example is available in the [README](https://github.com/Vunovati/pino-opentelemetry-transport#minimalistic-example).
<a id="communication-between-pino-and-transport"></a>

@@ -900,0 +991,0 @@ ## Communication between Pino and Transports

@@ -27,2 +27,3 @@ # Web Frameworks

})
fastify.get('/', async (request, reply) => {

@@ -32,2 +33,9 @@ request.log.info('something')

})
fastify.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
```

@@ -34,0 +42,0 @@

'use strict'
module.exports = { version: '8.8.0' }
module.exports = { version: '8.16.2' }

@@ -6,5 +6,2 @@ 'use strict'

const defaultLevels = Object.create(levels)
defaultLevels.silent = Infinity
const DEFAULT_INFO_LEVEL = levels.info

@@ -17,5 +14,8 @@

let levels = defaultLevels
const streamLevels = Object.create(levels)
streamLevels.silent = Infinity
if (opts.levels && typeof opts.levels === 'object') {
levels = opts.levels
Object.keys(opts.levels).forEach(i => {
streamLevels[i] = opts.levels[i]
})
}

@@ -31,3 +31,4 @@

clone,
[metadata]: true
[metadata]: true,
streamLevels
}

@@ -105,3 +106,3 @@

const { streams } = this
const { streams, streamLevels } = this

@@ -112,3 +113,3 @@ let level

} else if (typeof dest.level === 'string') {
level = levels[dest.level]
level = streamLevels[dest.level]
} else if (typeof dest.level === 'number') {

@@ -115,0 +116,0 @@ level = dest.level

@@ -23,2 +23,3 @@ 'use strict'

errorKeySym,
messageKeySym,
useOnlyCustomLevelsSym,

@@ -29,3 +30,4 @@ needsMetadataGsym,

formatOptsSym,
stringifiersSym
stringifiersSym,
msgPrefixSym
} = require('./symbols')

@@ -143,2 +145,6 @@ const {

if (typeof options.msgPrefix === 'string') {
instance[msgPrefixSym] = (this[msgPrefixSym] || '') + options.msgPrefix
}
instance[chindingsSym] = asChindings(instance, bindings)

@@ -182,2 +188,3 @@ const childLevel = options.level || this.level

const errorKey = this[errorKeySym]
const messageKey = this[messageKeySym]
const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy

@@ -195,3 +202,3 @@ let obj

obj = _obj
if (msg === undefined && _obj[errorKey]) {
if (msg === undefined && _obj[messageKey] === undefined && _obj[errorKey]) {
msg = _obj[errorKey].message

@@ -202,3 +209,3 @@ }

if (mixin) {
obj = mixinMergeStrategy(obj, mixin(obj, num))
obj = mixinMergeStrategy(obj, mixin(obj, num, this))
}

@@ -221,5 +228,12 @@

function flush () {
function flush (cb) {
if (cb != null && typeof cb !== 'function') {
throw Error('callback must be a function')
}
const stream = this[streamSym]
if ('flush' in stream) stream.flush(noop)
if (typeof stream.flush === 'function') {
stream.flush(cb || noop)
} else if (cb) cb()
}

@@ -30,2 +30,3 @@ 'use strict'

const mixinMergeStrategySym = Symbol('pino.mixinMergeStrategy')
const msgPrefixSym = Symbol('pino.msgPrefix')

@@ -70,3 +71,4 @@ const wildcardFirstSym = Symbol('pino.wildcardFirst')

nestedKeyStrSym,
mixinMergeStrategySym
mixinMergeStrategySym,
msgPrefixSym
}

@@ -24,3 +24,4 @@ 'use strict'

errorKeySym,
nestedKeyStrSym
nestedKeyStrSym,
msgPrefixSym
} = require('./symbols')

@@ -30,3 +31,4 @@ const { isMainThread } = require('worker_threads')

function noop () {}
function noop () {
}

@@ -57,5 +59,17 @@ function genLog (level, hook) {

}
// We do not use a coercive check for `msg` as it is
// measurably slower than the explicit checks.
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
msg = this[msgPrefixSym] + msg
}
this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)
} else {
this[writeSym](null, format(o === undefined ? n.shift() : o, n, this[formatOptsSym]), level)
let msg = o === undefined ? n.shift() : o
// We do not use a coercive check for `msg` as it is
// measurably slower than the explicit checks.
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
msg = this[msgPrefixSym] + msg
}
this[writeSym](null, format(msg, n, this[formatOptsSym]), level)
}

@@ -148,3 +162,4 @@ }

if (value === undefined) continue
propStr += ',"' + key + '":' + value
const strKey = asString(key)
propStr += ',' + strKey + ':' + value
}

@@ -223,7 +238,11 @@ }

const hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE
function buildSafeSonicBoom (opts) {
const stream = new SonicBoom(opts)
stream.on('error', filterBrokenPipe)
// if we are sync: false, we must flush on exit
if (!opts.sync && isMainThread) {
// If we are sync: false, we must flush on exit
// We must disable this if there is node code coverage due to
// https://github.com/nodejs/node/issues/49344#issuecomment-1741776308.
if (!hasNodeCodeCoverage && !opts.sync && isMainThread) {
onExit.register(stream, autoEnd)

@@ -230,0 +249,0 @@

@@ -5,3 +5,3 @@ 'use strict'

const getCallers = require('./caller')
const { join, isAbsolute } = require('path')
const { join, isAbsolute, sep } = require('path')
const sleep = require('atomic-sleep')

@@ -75,3 +75,3 @@ const onExit = require('on-exit-leak-free')

function transport (fullOptions) {
const { pipeline, targets, levels, options = {}, worker = {}, caller = getCallers() } = fullOptions
const { pipeline, targets, levels, dedupe, options = {}, worker = {}, caller = getCallers() } = fullOptions

@@ -112,2 +112,6 @@ // Backwards compatibility

if (dedupe) {
options.dedupe = dedupe
}
return buildStream(fixTarget(target), options, worker)

@@ -130,3 +134,7 @@

try {
fixTarget = createRequire(filePath).resolve(origin)
const context = filePath === 'node:repl'
? process.cwd() + sep
: filePath
fixTarget = createRequire(context).resolve(origin)
break

@@ -133,0 +141,0 @@ } catch (err) {

@@ -12,3 +12,3 @@ 'use strict'

module.exports = async function ({ targets, levels }) {
module.exports = async function ({ targets, levels, dedupe }) {
targets = await Promise.all(targets.map(async (t) => {

@@ -42,3 +42,3 @@ const fn = await loadTransportStreamBuilder(t.target)

function process (stream) {
const multi = pino.multistream(targets, { levels })
const multi = pino.multistream(targets, { levels, dedupe })
// TODO manage backpressure

@@ -45,0 +45,0 @@ stream.on('data', function (chunk) {

{
"name": "pino",
"version": "8.8.0",
"version": "8.16.2",
"description": "super fast, all natural json logger",

@@ -9,15 +9,2 @@ "main": "pino.js",

"browser": "./browser.js",
"files": [
"pino.js",
"file.js",
"pino.d.ts",
"bin.js",
"browser.js",
"pretty.js",
"usage.txt",
"test",
"docs",
"example.js",
"lib"
],
"scripts": {

@@ -33,2 +20,6 @@ "docs": "docsify serve",

"test-types": "tsc && tsd && ts-node test/types/pino.ts",
"test:smoke": "smoker smoke:pino && smoker smoke:browser && smoker smoke:file",
"smoke:pino": "node ./pino.js",
"smoke:browser": "node ./browser.js",
"smoke:file": "node ./file.js",
"transpile": "node ./test/fixtures/ts/transpile.cjs",

@@ -75,7 +66,7 @@ "cov-ui": "tap --ts --coverage-report=html",

"@types/flush-write-stream": "^1.0.0",
"@types/node": "^18.0.0",
"@types/node": "^20.2.3",
"@types/tap": "^15.0.6",
"airtap": "4.0.4",
"benchmark": "^2.1.4",
"bole": "^4.0.0",
"bole": "^5.0.5",
"bunyan": "^1.8.14",

@@ -87,3 +78,3 @@ "debug": "^4.3.4",

"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.2",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-node": "^11.1.0",

@@ -98,7 +89,8 @@ "eslint-plugin-promise": "^6.0.0",

"loglevel": "^1.6.7",
"pino-pretty": "^9.0.0",
"midnight-smoker": "1.1.1",
"pino-pretty": "^10.2.1",
"pre-commit": "^1.2.2",
"proxyquire": "^2.1.3",
"pump": "^3.0.0",
"rimraf": "^3.0.2",
"rimraf": "^5.0.1",
"semver": "^7.3.7",

@@ -113,3 +105,3 @@ "split2": "^4.0.0",

"tsd": "^0.24.1",
"typescript": "^4.8.2",
"typescript": "^5.1.3",
"winston": "^3.7.2"

@@ -121,3 +113,3 @@ },

"on-exit-leak-free": "^2.1.0",
"pino-abstract-transport": "v1.0.0",
"pino-abstract-transport": "v1.1.0",
"pino-std-serializers": "^6.0.0",

@@ -128,3 +120,3 @@ "process-warning": "^2.0.0",

"safe-stable-stringify": "^2.3.1",
"sonic-boom": "^3.1.0",
"sonic-boom": "^3.7.0",
"thread-stream": "^2.0.0"

@@ -131,0 +123,0 @@ },

@@ -1,2 +0,1 @@

// Type definitions for pino 7.0
// Project: https://github.com/pinojs/pino.git, http://getpino.io

@@ -43,3 +42,3 @@ // Definitions by: Peter Snider <https://github.com/psnider>

interface redactOptions {
export interface redactOptions {
paths: string[];

@@ -50,3 +49,3 @@ censor?: string | ((value: any, path: string[]) => any);

interface LoggerExtras<Options = LoggerOptions> extends EventEmitter {
export interface LoggerExtras<Options = LoggerOptions> extends EventEmitter {
/**

@@ -86,3 +85,3 @@ * Exposes the Pino package version. Also available on the exported pino function.

*/
child<ChildOptions extends pino.ChildLoggerOptions>(bindings: pino.Bindings, options?: ChildOptions): pino.Logger<Options & ChildOptions>;
child<ChildOptions extends pino.ChildLoggerOptions = {}>(bindings: pino.Bindings, options?: ChildOptions): pino.Logger<Options & ChildOptions>;

@@ -112,3 +111,3 @@ /**

*/
isLevelEnabled(level: pino.LevelWithSilent | string): boolean;
isLevelEnabled(level: pino.LevelWithSilentOrString): boolean;

@@ -130,4 +129,5 @@ /**

* Flushes the content of the buffer when using pino.destination({ sync: false }).
* call the callback when finished
*/
flush(): () => void;
flush(cb?: (err?: Error) => void): void;
}

@@ -155,3 +155,3 @@

*/
level: pino.LevelWithSilent | string;
level: pino.LevelWithSilentOrString;

@@ -227,3 +227,5 @@ /**

type Level = "fatal" | "error" | "warn" | "info" | "debug" | "trace";
type LevelOrString = Level | (string & {});
type LevelWithSilent = pino.Level | "silent";
type LevelWithSilentOrString = LevelWithSilent | (string & {});

@@ -234,5 +236,5 @@ type SerializerFn = (value: any) => any;

type LevelChangeEventListener<Options = LoggerOptions> = (
lvl: LevelWithSilent | string,
lvl: LevelWithSilentOrString,
val: number,
prevLvl: LevelWithSilent | string,
prevLvl: LevelWithSilentOrString,
prevVal: number,

@@ -253,4 +255,4 @@ logger: Logger<Options>

target: string
options: TransportOptions
level: LevelWithSilent | string
options?: TransportOptions
level?: LevelWithSilentOrString
}

@@ -274,2 +276,3 @@

levels?: Record<string, number>
dedupe?: boolean
}

@@ -297,14 +300,14 @@

interface StreamEntry {
interface StreamEntry<TLevel = Level> {
stream: DestinationStream
level?: Level
level?: TLevel
}
interface MultiStreamRes {
interface MultiStreamRes<TOriginLevel = Level> {
write: (data: any) => void,
add: (dest: StreamEntry | DestinationStream) => MultiStreamRes,
add: <TLevel = Level>(dest: StreamEntry<TLevel> | DestinationStream) => MultiStreamRes<TOriginLevel & TLevel>,
flushSync: () => void,
minLevel: number,
streams: StreamEntry[],
clone(level: Level): MultiStreamRes,
streams: StreamEntry<TOriginLevel>[],
clone<TLevel = Level>(level: TLevel): MultiStreamRes<TLevel>,
}

@@ -358,3 +361,3 @@

*/
level?: LevelWithSilent | string;
level?: LevelWithSilentOrString;

@@ -418,6 +421,2 @@ /**

/**
* Allows to optionally define which prettifier module to use.
*/
prettifier?: any;
/**
* Enables logging. Default: `true`.

@@ -565,3 +564,3 @@ */

*/
level?: Level | string;
level?: LevelOrString;
/**

@@ -574,2 +573,9 @@ * Remotely record log messages.

};
/**
* The disabled option will disable logging in browser if set to true, by default it is set to false.
*
* @example
* const pino = require('pino')({browser: {disabled: true}})
*/
disabled?: boolean;
};

@@ -611,2 +617,7 @@ /**

/**
* A string that would be prefixed to every message (and child message)
*/
msgPrefix?: string
/**
* An object mapping to hook functions. Hook functions allow for customizing internal logger operations.

@@ -639,6 +650,11 @@ * Hook functions must be synchronous functions.

onChild?: OnChildCallback;
/**
* logs newline delimited JSON with `\r\n` instead of `\n`. Default: `false`.
*/
crlf?: boolean;
}
interface ChildLoggerOptions {
level?: Level | string;
level?: LevelOrString;
serializers?: { [key: string]: SerializerFn };

@@ -652,2 +668,3 @@ customLevels?: { [key: string]: number };

redact?: string[] | redactOptions;
msgPrefix?: string
}

@@ -782,6 +799,6 @@

export function multistream(
streamsArray: (DestinationStream | StreamEntry)[] | DestinationStream | StreamEntry,
export function multistream<TLevel = Level>(
streamsArray: (DestinationStream | StreamEntry<TLevel>)[] | DestinationStream | StreamEntry<TLevel>,
opts?: MultiStreamOptions
): MultiStreamRes
): MultiStreamRes<TLevel>
}

@@ -822,3 +839,5 @@

export type Level = pino.Level;
export type LevelOrString = pino.LevelOrString;
export type LevelWithSilent = pino.LevelWithSilent;
export type LevelWithSilentOrString = pino.LevelWithSilentOrString;
export type LevelChangeEventListener = pino.LevelChangeEventListener;

@@ -842,4 +861,4 @@ export type LogDescriptor = pino.LogDescriptor;

export interface MultiStreamOptions extends pino.MultiStreamOptions {}
export interface MultiStreamRes extends pino.MultiStreamRes {}
export interface StreamEntry extends pino.StreamEntry {}
export interface MultiStreamRes<TLevel = Level> extends pino.MultiStreamRes<TLevel> {}
export interface StreamEntry<TLevel = Level> extends pino.StreamEntry<TLevel> {}
export interface TransportBaseOptions extends pino.TransportBaseOptions {}

@@ -846,0 +865,0 @@ export interface TransportMultiOptions extends pino.TransportMultiOptions {}

@@ -43,3 +43,4 @@ 'use strict'

nestedKeyStrSym,
mixinMergeStrategySym
mixinMergeStrategySym,
msgPrefixSym
} = symbols

@@ -107,3 +108,4 @@ const { epochTime, nullTime } = time

edgeLimit,
onChild
onChild,
msgPrefix
} = opts

@@ -155,2 +157,3 @@

if (mixin && typeof mixin !== 'function') throw Error(`Unknown mixin type "${typeof mixin}" - expected "function"`)
if (msgPrefix && typeof msgPrefix !== 'string') throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`)

@@ -183,3 +186,4 @@ assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels)

silent: noop,
onChild
onChild,
[msgPrefixSym]: msgPrefix
})

@@ -186,0 +190,0 @@

@@ -5,3 +5,3 @@ ![banner](pino-banner.png)

[![npm version](https://img.shields.io/npm/v/pino)](https://www.npmjs.com/package/pino)
[![Build Status](https://img.shields.io/github/workflow/status/pinojs/pino/CI)](https://github.com/pinojs/pino/actions)
[![Build Status](https://img.shields.io/github/actions/workflow/status/pinojs/pino/ci.yml)](https://github.com/pinojs/pino/actions)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)

@@ -28,2 +28,3 @@

Using NPM:
```

@@ -33,2 +34,7 @@ $ npm install pino

Using YARN:
```
$ yarn add pino
```
If you would like to install pino v6, refer to https://github.com/pinojs/pino/tree/v6.x.

@@ -107,3 +113,3 @@

<https://github.com/pinojs>
<https://github.com/mcollina>

@@ -110,0 +116,0 @@ <https://www.npmjs.com/~matteo.collina>

@@ -423,2 +423,19 @@ 'use strict'

test('correctly escape quote in a key', async ({ same }) => {
const stream = sink()
const instance = pino(stream)
const obj = { 'some"obj': 'world' }
instance.info(obj, 'a string')
const result = await once(stream, 'data')
delete result.time
same(result, {
level: 30,
pid,
hostname,
msg: 'a string',
'some"obj': 'world'
})
same(Object.keys(obj), ['some"obj'])
})
// https://github.com/pinojs/pino/issues/139

@@ -755,1 +772,72 @@ test('object and format string', async ({ same }) => {

})
test('logger message should have the prefix message that defined in the logger creation', async ({ equal }) => {
const stream = sink()
const logger = pino({
msgPrefix: 'My name is Bond '
}, stream)
logger.info('James Bond')
const { msg } = await once(stream, 'data')
equal(msg, 'My name is Bond James Bond')
})
test('child message should have the prefix message that defined in the child creation', async ({ equal }) => {
const stream = sink()
const instance = pino(stream)
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
child.info('James Bond')
const { msg } = await once(stream, 'data')
equal(msg, 'My name is Bond James Bond')
})
test('child message should have the prefix message that defined in the child creation when logging with log meta', async ({ equal }) => {
const stream = sink()
const instance = pino(stream)
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
child.info({ hello: 'world' }, 'James Bond')
const { msg, hello } = await once(stream, 'data')
equal(hello, 'world')
equal(msg, 'My name is Bond James Bond')
})
test('logged message should not have the prefix when not providing any message', async ({ equal }) => {
const stream = sink()
const instance = pino(stream)
const child = instance.child({}, { msgPrefix: 'This should not be shown ' })
child.info({ hello: 'world' })
const { msg, hello } = await once(stream, 'data')
equal(hello, 'world')
equal(msg, undefined)
})
test('child message should append parent prefix to current prefix that defined in the child creation', async ({ equal }) => {
const stream = sink()
const instance = pino({
msgPrefix: 'My name is Bond '
}, stream)
const child = instance.child({}, { msgPrefix: 'James ' })
child.info('Bond')
const { msg } = await once(stream, 'data')
equal(msg, 'My name is Bond James Bond')
})
test('child message should inherent parent prefix', async ({ equal }) => {
const stream = sink()
const instance = pino({
msgPrefix: 'My name is Bond '
}, stream)
const child = instance.child({})
child.info('James Bond')
const { msg } = await once(stream, 'data')
equal(msg, 'My name is Bond James Bond')
})
test('grandchild message should inherent parent prefix', async ({ equal }) => {
const stream = sink()
const instance = pino(stream)
const child = instance.child({}, { msgPrefix: 'My name is Bond ' })
const grandchild = child.child({})
grandchild.info('James Bond')
const { msg } = await once(stream, 'data')
equal(msg, 'My name is Bond James Bond')
})

@@ -14,2 +14,12 @@ 'use strict'

if (process.env.CITGM) {
// This looks like a some form of limitations of the CITGM test runner
// or the HW/SW we run it on. This file can hang on Node.js v18.x.
// The failure does not reproduce locally or on our CI.
// Skipping it is the only way to keep pino in CITGM.
// https://github.com/nodejs/citgm/pull/1002#issuecomment-1751942988
t.skip('Skipping on Node.js core CITGM because it hangs on v18.x')
process.exit(0)
}
function test (file) {

@@ -16,0 +26,0 @@ file = join('fixtures', 'broken-pipe', file)

@@ -118,2 +118,25 @@ 'use strict'

test('set custom level and use it', ({ end, same, is }) => {
const expected = [
{
level: 31,
msg: 'this is a custom level'
}
]
const instance = pino({
customLevels: {
success: 31
},
browser: {
write (actual) {
checkLogObjects(is, same, actual, expected.shift())
}
}
})
instance.success('this is a custom level')
end()
})
test('the wrong level throws', ({ end, throws }) => {

@@ -120,0 +143,0 @@ const instance = pino()

@@ -359,1 +359,41 @@ 'use strict'

})
test('msg should take precedence over error message on mergingObject', async ({ same }) => {
const err = new Error('myerror')
const stream = sink()
const instance = pino(stream)
instance.error({ msg: 'my message', err })
const result = await once(stream, 'data')
delete result.time
same(result, {
pid,
hostname,
level: 50,
err: {
type: 'Error',
stack: err.stack,
message: err.message
},
msg: 'my message'
})
})
test('considers messageKey when giving msg precedence over error', async ({ same }) => {
const err = new Error('myerror')
const stream = sink()
const instance = pino({ messageKey: 'message' }, stream)
instance.error({ message: 'my message', err })
const result = await once(stream, 'data')
delete result.time
same(result, {
pid,
hostname,
level: 50,
err: {
type: 'Error',
stack: err.stack,
message: err.message
},
message: 'my message'
})
})
'use strict'
const { Writable } = require('stream')
const fs = require('fs')
module.exports = (options) => {

@@ -8,3 +9,4 @@ const myTransportStream = new Writable({

write (chunk, enc, cb) {
console.log(chunk.toString())
// Bypass console.log() to avoid flakyness
fs.writeSync(1, chunk.toString())
cb()

@@ -11,0 +13,0 @@ }

@@ -163,1 +163,57 @@ 'use strict'

})
test('mixin receives logger as third parameter', async ({ ok, same }) => {
const stream = sink()
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger, instance)
return { ...context, num }
}
}, stream)
instance.level = name
instance[name]({
message: '123'
}, 'test')
})
test('mixin receives child logger', async ({ ok, same }) => {
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger.expected, child.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
child[name]({
message: '123'
}, 'test')
})
test('mixin receives logger even if child exists', async ({ ok, same }) => {
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
ok(logger !== null, 'logger should be defined')
ok(logger !== undefined, 'logger should be defined')
same(logger.expected, instance.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
instance[name]({
message: '123'
}, 'test')
})

@@ -224,3 +224,3 @@ 'use strict'

const nested = proxyquire('pino-pretty/lib/utils', {
const safeBoom = proxyquire('pino-pretty/lib/utils/build-safe-sonic-boom.js', {
'sonic-boom': function () {

@@ -233,4 +233,7 @@ t.pass('sonic created')

})
const nested = proxyquire('pino-pretty/lib/utils/index.js', {
'./build-safe-sonic-boom.js': safeBoom
})
const pretty = proxyquire('pino-pretty', {
'./lib/utils': nested
'./lib/utils/index.js': nested
})

@@ -237,0 +240,0 @@

'use strict'
const os = require('os')
const { createWriteStream } = require('fs')
const {
createWriteStream
} = require('fs')
const { readFile } = require('fs').promises
const { join } = require('path')

@@ -9,5 +12,16 @@ const { test } = require('tap')

const writer = require('flush-write-stream')
const { once, getPathToNull } = require('./helper')
const {
once,
getPathToNull,
file,
watchFileCreated
} = require('./helper')
const { promisify } = require('util')
test('asynchronous logging', async ({ equal, teardown }) => {
const sleep = promisify(setTimeout)
test('asynchronous logging', async ({
equal,
teardown
}) => {
const now = Date.now

@@ -52,2 +66,4 @@ const hostname = os.hostname

await once(child, 'close')
// Wait for the last write to be flushed
await sleep(100)
equal(actual, expected)

@@ -63,3 +79,6 @@ equal(actual2.trim(), expected2)

test('sync false with child', async ({ equal, teardown }) => {
test('sync false with child', async ({
equal,
teardown
}) => {
const now = Date.now

@@ -88,3 +107,5 @@ const hostname = os.hostname

const dest = createWriteStream(getPathToNull())
dest.write = function (s) { actual += s }
dest.write = function (s) {
actual += s
}
const asyncLogger = pino(dest).child({ hello: 'world' })

@@ -119,5 +140,57 @@

test('flush does nothing with sync true (default)', async () => {
test('flush does nothing with sync true (default)', async ({ equal }) => {
const instance = require('..')()
instance.flush()
equal(instance.flush(), undefined)
})
test('should still call flush callback even when does nothing with sync true (default)', (t) => {
t.plan(3)
const instance = require('..')()
instance.flush((...args) => {
t.ok('flush called')
t.same(args, [])
// next tick to make flush not called more than once
process.nextTick(() => {
t.ok('flush next tick called')
})
})
})
test('should call the flush callback when flushed the data for async logger', async (t) => {
const outputPath = file()
async function getOutputLogLines () {
return (await readFile(outputPath)).toString().trim().split('\n').map(JSON.parse)
}
const pino = require('../')
const instance = pino({}, pino.destination({
dest: outputPath,
// to make sure it does not flush on its own
minLength: 4096
}))
const flushPromise = promisify(instance.flush).bind(instance)
instance.info('hello')
await flushPromise()
await watchFileCreated(outputPath)
const [firstFlushData] = await getOutputLogLines()
t.equal(firstFlushData.msg, 'hello')
// should not flush this as no data accumulated that's bigger than min length
instance.info('world')
// Making sure data is not flushed yet
const afterLogData = await getOutputLogLines()
t.equal(afterLogData.length, 1)
await flushPromise()
// Making sure data is not flushed yet
const afterSecondFlush = (await getOutputLogLines())[1]
t.equal(afterSecondFlush.msg, 'world')
})

@@ -16,3 +16,5 @@ 'use strict'

test('eight million lines', async ({ equal, comment }) => {
const skip = process.env.CI || process.env.CITGM
test('eight million lines', { skip }, async ({ equal, comment }) => {
const destination = file()

@@ -19,0 +21,0 @@ await execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-many-lines.js'), destination])

@@ -204,2 +204,64 @@ 'use strict'

test('pino.transport without specifying default levels', async ({ same, teardown }) => {
const dest = file()
const transport = pino.transport({
targets: [{
level: 'foo',
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
options: { destination: dest }
}],
levels: { foo: 25 }
})
teardown(transport.end.bind(transport))
const instance = pino(transport)
instance.info('hello')
await Promise.all([watchFileCreated(dest)])
const result1 = JSON.parse(await readFile(dest))
delete result1.time
same(result1, {
pid,
hostname,
level: 30,
msg: 'hello'
})
})
test('pino.transport with two files and dedupe', async ({ same, teardown }) => {
const dest1 = file()
const dest2 = file()
const transport = pino.transport({
dedupe: true,
targets: [{
level: 'info',
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
options: { destination: dest1 }
}, {
level: 'error',
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
options: { destination: dest2 }
}]
})
teardown(transport.end.bind(transport))
const instance = pino(transport)
instance.info('hello')
instance.error('world')
await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
const result1 = JSON.parse(await readFile(dest1))
delete result1.time
same(result1, {
pid,
hostname,
level: 30,
msg: 'hello'
})
const result2 = JSON.parse(await readFile(dest2))
delete result2.time
same(result2, {
pid,
hostname,
level: 50,
msg: 'world'
})
})
test('pino.transport with an array including a pino-pretty destination', async ({ same, match, teardown }) => {

@@ -427,2 +489,3 @@ const dest1 = file()

await once(child, 'close')
await immediate()
not(strip(actual).match(/Hello/), null)

@@ -451,2 +514,3 @@ })

await once(child, 'close')
await immediate()
not(strip(actual).match(/Hello/), null)

@@ -453,0 +517,0 @@ })

@@ -9,2 +9,3 @@ 'use strict'

const { watchFileCreated, file } = require('../helper')
const { promisify } = require('util')

@@ -14,3 +15,3 @@ const { pid } = process

test('thread-stream async flush', async ({ same }) => {
test('thread-stream async flush', async ({ equal, same }) => {
const destination = file()

@@ -23,3 +24,5 @@ const transport = pino.transport({

instance.info('hello')
instance.flush()
equal(instance.flush(), undefined)
await watchFileCreated(destination)

@@ -35,1 +38,35 @@ const result = JSON.parse(await readFile(destination))

})
test('thread-stream async flush should call the passed callback', async (t) => {
const outputPath = file()
async function getOutputLogLines () {
return (await readFile(outputPath)).toString().trim().split('\n').map(JSON.parse)
}
const transport = pino.transport({
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
options: { destination: outputPath }
})
const instance = pino(transport)
const flushPromise = promisify(instance.flush).bind(instance)
instance.info('hello')
await flushPromise()
await watchFileCreated(outputPath)
const [firstFlushData] = await getOutputLogLines()
t.equal(firstFlushData.msg, 'hello')
// should not flush this as no data accumulated that's bigger than min length
instance.info('world')
// Making sure data is not flushed yet
const afterLogData = await getOutputLogLines()
t.equal(afterLogData.length, 1)
await flushPromise()
// Making sure data is not flushed yet
const afterSecondFlush = (await getOutputLogLines())[1]
t.equal(afterSecondFlush.msg, 'world')
})

@@ -5,4 +5,3 @@ import { expectType } from 'tsd'

import pino from '../../pino'
import { multistream } from "../../pino";
import pino, { multistream } from '../../pino'

@@ -13,3 +12,3 @@ const streams = [

{ level: 'error' as const, stream: process.stderr },
{ level: 'fatal' as const, stream: createWriteStream('') }
{ level: 'fatal' as const, stream: process.stderr },
]

@@ -19,11 +18,14 @@

expectType<pino.MultiStreamRes>(pino.multistream([createWriteStream('')]))
expectType<pino.MultiStreamRes>(pino.multistream({ level: 'error' as const, stream: process.stderr }))
expectType<pino.MultiStreamRes>(pino.multistream([{ level: 'fatal' as const, stream: createWriteStream('') }]))
expectType<pino.MultiStreamRes<'error'>>(pino.multistream({ level: 'error' as const, stream: process.stderr }))
expectType<pino.MultiStreamRes<'fatal'>>(pino.multistream([{ level: 'fatal' as const, stream: createWriteStream('') }]))
expectType<pino.MultiStreamRes>(pino.multistream(streams))
expectType<pino.MultiStreamRes>(pino.multistream(streams, {}))
expectType<pino.MultiStreamRes>(pino.multistream(streams, { levels: { 'info': 30 } }))
expectType<pino.MultiStreamRes>(pino.multistream(streams, { dedupe: true }))
expectType<pino.MultiStreamRes>(pino.multistream(streams[0]).add(streams[1]))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(pino.multistream(streams))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(pino.multistream(streams, {}))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(pino.multistream(streams, { levels: { 'info': 30 } }))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(pino.multistream(streams, { dedupe: true }))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(pino.multistream(streams[0]).add(streams[1]))
expectType<pino.MultiStreamRes<'error' | 'fatal'>>(multistream(streams))
expectType<pino.MultiStreamRes<'error'>>(multistream(streams).clone('error'))
expectType<pino.MultiStreamRes>(multistream(process.stdout));

@@ -77,2 +77,19 @@ import { pino } from '../../pino'

const transportsWithoutOptions = pino.transport({
targets: [
{ target: '#pino/pretty' },
{ target: '#pino/file' }
], levels: { foo: 35 }
})
pino(transports)
expectType<pino.Logger>(pino({
transport: {
targets: [
{ target: '#pino/pretty' },
{ target: '#pino/file' }
], levels: { foo: 35 }
},
}))
const pipelineTransport = pino.transport({

@@ -124,1 +141,7 @@ pipeline: [{

})
// Dedupe
pino.transport({
targets: [],
dedupe: true,
})

@@ -1,5 +0,5 @@

import { expectAssignable, expectType } from "tsd";
import { expectAssignable, expectType, expectNotAssignable } from "tsd";
import pino from "../../";
import type {LevelWithSilent, Logger, LogFn, P, DestinationStreamWithMetadata } from "../../pino";
import type {LevelWithSilent, Logger, LogFn, P, DestinationStreamWithMetadata, Level, LevelOrString, LevelWithSilentOrString, LoggerExtras } from "../../pino";

@@ -9,2 +9,3 @@ // NB: can also use `import * as pino`, but that form is callable as `pino()`

const log = pino();
expectAssignable<LoggerExtras>(log);
expectType<Logger>(log);

@@ -16,5 +17,24 @@ expectType<LogFn>(log.info);

const level: LevelWithSilent = 'silent';
expectAssignable<P.LevelWithSilent>(level);
expectType<Parameters<typeof log.isLevelEnabled>>([log.level]);
const level: Level = 'debug';
expectAssignable<string>(level);
expectAssignable<P.Level>(level);
const levelWithSilent: LevelWithSilent = 'silent';
expectAssignable<string>(levelWithSilent);
expectAssignable<P.LevelWithSilent>(levelWithSilent);
const levelOrString: LevelOrString = "myCustomLevel";
expectAssignable<string>(levelOrString);
expectNotAssignable<pino.Level>(levelOrString);
expectNotAssignable<pino.LevelWithSilent>(levelOrString);
expectAssignable<pino.LevelWithSilentOrString>(levelOrString);
const levelWithSilentOrString: LevelWithSilentOrString = "myCustomLevel";
expectAssignable<string>(levelWithSilentOrString);
expectNotAssignable<pino.Level>(levelWithSilentOrString);
expectNotAssignable<pino.LevelWithSilent>(levelWithSilentOrString);
expectAssignable<pino.LevelOrString>(levelWithSilentOrString);
function createStream(): DestinationStreamWithMetadata {

@@ -21,0 +41,0 @@ return { write() {} };

@@ -114,2 +114,4 @@ import P, { pino } from "../../";

expectType<void>(log.flush());
log.flush((err?: Error) => undefined);
log.child({ a: "property" }).info("hello child!");

@@ -329,1 +331,17 @@ log.level = "error";

pino({
crlf: true,
});
const customLevels = { foo: 99 };
const customLevelLogger = pino({ customLevels });
type CustomLevelLogger = typeof customLevelLogger
type CustomLevelLoggerLevels = pino.Level | keyof typeof customLevels
const fn = (logger: Pick<CustomLevelLogger, CustomLevelLoggerLevels>) => {}
const customLevelChildLogger = customLevelLogger.child({ name: "child" })
fn(customLevelChildLogger); // missing foo typing

@@ -1,4 +0,5 @@

import { pino } from '../../pino'
import { StreamEntry, pino } from '../../pino'
import { join } from 'path'
import { tmpdir } from 'os'
import pinoPretty from 'pino-pretty'

@@ -43,1 +44,36 @@ const destination = join(

loggerMulti.info('test2')
// custom levels
const customLevels = {
debug : 1,
info : 2,
network : 3,
error : 4,
};
type CustomLevels = keyof typeof customLevels;
const pinoOpts = {
level: 'debug',
useOnlyCustomLevels: true,
customLevels: customLevels,
};
const multistreamOpts = {
dedupe: true,
levels: customLevels
};
const streams: StreamEntry<CustomLevels>[] = [
{ level : 'debug', stream : pinoPretty() },
{ level : 'info', stream : pinoPretty() },
{ level : 'network', stream : pinoPretty() },
{ level : 'error', stream : pinoPretty() },
];
const loggerCustomLevel = pino(pinoOpts, pino.multistream(streams, multistreamOpts));
loggerCustomLevel.debug('test3')
loggerCustomLevel.info('test4')
loggerCustomLevel.error('test5')
loggerCustomLevel.network('test6')
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc