Comparing version 7.6.5 to 7.11.0
153
docs/api.md
@@ -33,2 +33,8 @@ # API | ||
* [pino.version](#pino-version) | ||
* [Interfaces](#interfaces) | ||
* [MultiStreamRes](#multistreamres) | ||
* [StreamEntry](#streamentry) | ||
* [DestinationStream](#destinationstream) | ||
* [Types](#types) | ||
* [Level](#level-1) | ||
@@ -111,2 +117,3 @@ <a id="export"></a> | ||
<a id="opt-mixin"></a> | ||
#### `mixin` (Function): | ||
@@ -117,4 +124,4 @@ | ||
If provided, the `mixin` function is called each time one of the active | ||
logging methods is called. The first and only parameter is the value `mergeObject` or an empty object. The function must synchronously return an | ||
object. The properties of the returned object will be added to the | ||
logging methods is called. The first parameter is the value `mergeObject` or an empty object. The second parameter is the log level number. | ||
The function must synchronously return an object. The properties of the returned object will be added to the | ||
logged JSON. | ||
@@ -136,3 +143,4 @@ | ||
The result of `mixin()` is supposed to be a _new_ object. For performance reason, the object returned by `mixin()` will be mutated by pino. | ||
In the following example, passing `mergingObject` argument to the first `info` call will mutate the global `mixin` object: | ||
In the following example, passing `mergingObject` argument to the first `info` call will mutate the global `mixin` object by default: | ||
(* See [`mixinMergeStrategy` option](#opt-mixin-merge-strategy)): | ||
```js | ||
@@ -152,3 +160,3 @@ const mixin = { | ||
}, 'Message 1') | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","description":"Ok" "msg":"Message 1"} | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","description":"Ok","msg":"Message 1"} | ||
logger.info('Message 2') | ||
@@ -159,5 +167,82 @@ // {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","description":"Ok","msg":"Message 2"} | ||
The `mixin` method can be used to add the level label to each log message such as in the following example: | ||
```js | ||
const logger = pino({ | ||
mixin(_context, level) { | ||
return { 'level-label': logger.levels.labels[level] } | ||
} | ||
}) | ||
logger.info({ | ||
description: 'Ok' | ||
}, 'Message 1') | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","appName":"My app","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"} | ||
``` | ||
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. | ||
<a id="opt-mixin-merge-strategy"></a> | ||
#### `mixinMergeStrategy` (Function): | ||
Default: `undefined` | ||
If provided, the `mixinMergeStrategy` function is called each time one of the active | ||
logging methods is called. The first parameter is the value `mergeObject` or an empty object, | ||
the second parameter is the value resulting from `mixin()` (* See [`mixin` option](#opt-mixin) or an empty object. | ||
The function must synchronously return an object. | ||
```js | ||
// Default strategy, `mergeObject` has priority | ||
const logger = pino({ | ||
mixin() { | ||
return { tag: 'docker' } | ||
}, | ||
// mixinMergeStrategy(mergeObject, mixinObject) { | ||
// return Object.assign(mixinMeta, mergeObject) | ||
// } | ||
}) | ||
logger.info({ | ||
tag: 'local' | ||
}, 'Message') | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","tag":"local","msg":"Message"} | ||
``` | ||
```js | ||
// Custom mutable strategy, `mixin` has priority | ||
const logger = pino({ | ||
mixin() { | ||
return { tag: 'k8s' } | ||
}, | ||
mixinMergeStrategy(mergeObject, mixinObject) { | ||
return Object.assign(mergeObject, mixinObject) | ||
} | ||
}) | ||
logger.info({ | ||
tag: 'local' | ||
}, 'Message') | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","tag":"k8s","msg":"Message"} | ||
``` | ||
```js | ||
// Custom immutable strategy, `mixin` has priority | ||
const logger = pino({ | ||
mixin() { | ||
return { tag: 'k8s' } | ||
}, | ||
mixinMergeStrategy(mergeObject, mixinObject) { | ||
return Object.assign({}, mergeObject, mixinObject) | ||
} | ||
}) | ||
logger.info({ | ||
tag: 'local' | ||
}, 'Message') | ||
// {"level":30,"time":1591195061437,"pid":16012,"hostname":"x","tag":"k8s","msg":"Message"} | ||
``` | ||
<a id="opt-redact"></a> | ||
@@ -233,2 +318,4 @@ #### `redact` (Array | Object): | ||
ps: The log level cannot be customized when using multiple transports | ||
```js | ||
@@ -1111,5 +1198,6 @@ const formatters = { | ||
### `pino.multistream(options) => Stream` | ||
### `pino.multistream(streamsArray, opts) => MultiStreamRes` | ||
Create a stream composed by multiple destination streams: | ||
Create a stream composed by multiple destination streams and returns an | ||
object implementing the [MultiStreamRes](#multistreamres) interface. | ||
@@ -1220,1 +1308,54 @@ ```js | ||
* See [`logger.version`](#version) | ||
## Interfaces | ||
<a id="pino-multistreamres"></a> | ||
### `MultiStreamRes` | ||
Properties: | ||
* `write(data)` | ||
- `data` Object | string | ||
- Returns: void | ||
Write `data` onto the streams held by the current instance. | ||
* `add(dest)` | ||
- `dest` [StreamEntry](#streamentry) | [DestinationStream](#destinationstream) | ||
- Returns: [MultiStreamRes](#multistreamres) | ||
Add `dest` stream to the array of streams of the current instance. | ||
* `flushSync()` | ||
- Returns: `undefined` | ||
Call `flushSync` on each stream held by the current instance. | ||
* `minLevel` | ||
- number | ||
The minimum level amongst all the streams held by the current instance. | ||
* `streams` | ||
- Returns: [StreamEntry[]](#streamentry) | ||
The array of streams currently held by the current instance. | ||
* `clone(level)` | ||
- `level` [Level](#level-1) | ||
- Returns: [MultiStreamRes](#multistreamres) | ||
Returns a cloned object of the current instance but with the the provided `level`. | ||
### `StreamEntry` | ||
Properties: | ||
* `stream` | ||
- DestinationStream | ||
* `level` | ||
- Optional: [Level](#level-1) | ||
### `DestinationStream` | ||
Properties: | ||
* `write(msg)` | ||
- `msg` string | ||
## Types | ||
### `Level` | ||
* Values: `"fatal"` | `"error"` | `"warn"` | `"info"` | `"debug"` | `"trace"` |
@@ -74,1 +74,2 @@ # Pino Ecosystem | ||
+ [`pino-dev`](https://github.com/dnjstrom/pino-dev): simple prettifier for pino with built-in support for common ecosystem packages. | ||
+ [`@newrelic/pino-enricher`](https://github.com/newrelic/newrelic-node-log-extensions/blob/main/packages/pino-log-enricher): a log customization to add New Relic context to use [Logs In Context](https://docs.newrelic.com/docs/logs/logs-context/logs-in-context/) |
@@ -93,3 +93,3 @@ # Transports | ||
{ 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' }} | ||
] | ||
@@ -100,2 +100,15 @@ }) | ||
If we're using custom levels, they should be passed in when using more than one transport. | ||
```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' } | ||
], | ||
levels: { foo: 35 } | ||
}) | ||
pino(transport) | ||
``` | ||
For more details on `pino.transport` see the [API docs for `pino.transport`][pino-transport]. | ||
@@ -228,2 +241,18 @@ | ||
### TypeScript compatibility | ||
Pino provides basic support for transports written in TypeScript. | ||
Ideally, they should be transpiled to ensure maximum compatibility, but some | ||
times you might want to use tools such as TS-Node, to execute your TypeScript | ||
code without having to go through an explicit transpilation step. | ||
You can use your TypeScript code without explicit transpilation, but there are | ||
some known caveats: | ||
- For "pure" TypeScript code, ES imports are still not supported (ES imports are | ||
supported once the code is transpiled). | ||
- Only TS-Node is supported for now, there's no TSM support. | ||
- Running transports TypeScript code on TS-Node seems to be problematic on | ||
Windows systems, there's no official support for that yet. | ||
### Notable transports | ||
@@ -354,2 +383,3 @@ | ||
+ [pino-pretty](#pino-pretty) | ||
+ [pino-loki](#pino-loki) | ||
@@ -368,2 +398,3 @@ ### Legacy | ||
+ [pino-logflare](#pino-logflare) | ||
+ [pino-loki](#pino-loki) | ||
+ [pino-mq](#pino-mq) | ||
@@ -560,2 +591,24 @@ + [pino-mysql](#pino-mysql) | ||
<a id="pino-loki"></a> | ||
### pino-loki | ||
pino-loki is a transport that will forwards logs into [Grafana Loki](https://grafana.com/oss/loki/) | ||
Can be used in CLI version in a separate process or in a dedicated worker : | ||
CLI : | ||
```console | ||
node app.js | pino-loki --hostname localhost:3100 --labels='{ "application": "my-application"}' --user my-username --password my-password | ||
``` | ||
Worker : | ||
```js | ||
const pino = require('pino') | ||
const transport = pino.transport({ | ||
target: 'pino-loki', | ||
options: { hostname: 'localhost:3100' } | ||
}) | ||
pino(transport) | ||
``` | ||
For full documentation and configuration, see the [readme](https://github.com/Julien-R44/pino-loki) | ||
<a id="pino-papertrail"></a> | ||
@@ -562,0 +615,0 @@ ### pino-papertrail |
@@ -14,2 +14,3 @@ # Web Frameworks | ||
- [Pino with Nest](#pino-with-nest) | ||
- [Pino with H3](#pino-with-h3) | ||
@@ -231,1 +232,28 @@ <a id="fastify"></a> | ||
See the [nestjs-pino readme](https://npm.im/nestjs-pino) for more info. | ||
<a id="h3"></a> | ||
## Pino with H3 | ||
```sh | ||
npm install pino-http | ||
``` | ||
```js | ||
import { createServer } from 'http' | ||
import { createApp } from 'h3' | ||
import pino from 'pino-http' | ||
const app = createApp() | ||
app.use(pino()) | ||
app.use('/', (req) => { | ||
req.log.info('something') | ||
return 'hello world' | ||
}) | ||
createServer(app).listen(process.env.PORT || 3000) | ||
``` | ||
See the [pino-http readme](https://npm.im/pino-http) for more info. |
@@ -9,5 +9,6 @@ 'use strict' | ||
const DEFAULT_INFO_LEVEL = levels.info | ||
function multistream (streamsArray, opts) { | ||
let counter = 0 | ||
streamsArray = streamsArray || [] | ||
@@ -81,18 +82,35 @@ opts = opts || { dedupe: false } | ||
function add (dest) { | ||
if (!dest) { | ||
return res | ||
} | ||
// Check that dest implements either StreamEntry or DestinationStream | ||
const isStream = typeof dest.write === 'function' || dest.stream | ||
const stream_ = dest.write ? dest : dest.stream | ||
// This is necessary to provide a meaningful error message, otherwise it throws somewhere inside write() | ||
if (!isStream) { | ||
throw Error('stream object needs to implement either StreamEntry or DestinationStream interface') | ||
} | ||
const { streams } = this | ||
if (typeof dest.write === 'function') { | ||
return add.call(this, { stream: dest }) | ||
} else if (typeof dest.levelVal === 'number') { | ||
return add.call(this, Object.assign({}, dest, { level: dest.levelVal, levelVal: undefined })) | ||
let level | ||
if (typeof dest.levelVal === 'number') { | ||
level = dest.levelVal | ||
} else if (typeof dest.level === 'string') { | ||
return add.call(this, Object.assign({}, dest, { level: levels[dest.level] })) | ||
} else if (typeof dest.level !== 'number') { | ||
// we default level to 'info' | ||
dest = Object.assign({}, dest, { level: 30 }) | ||
level = levels[dest.level] | ||
} else if (typeof dest.level === 'number') { | ||
level = dest.level | ||
} else { | ||
dest = Object.assign({}, dest) | ||
level = DEFAULT_INFO_LEVEL | ||
} | ||
dest.id = counter++ | ||
streams.unshift(dest) | ||
const dest_ = { | ||
stream: stream_, | ||
level, | ||
levelVal: undefined, | ||
id: counter++ | ||
} | ||
streams.unshift(dest_) | ||
streams.sort(compareByLevel) | ||
@@ -99,0 +117,0 @@ |
@@ -16,2 +16,3 @@ 'use strict' | ||
writeSym, | ||
mixinMergeStrategySym, | ||
timeSym, | ||
@@ -162,11 +163,24 @@ timeSliceIndexSym, | ||
/** | ||
* Default strategy for creating `mergeObject` from arguments and the result from `mixin()`. | ||
* Fields from `mergeObject` have higher priority in this strategy. | ||
* | ||
* @param {Object} mergeObject The object a user has supplied to the logging function. | ||
* @param {Object} mixinObject The result of the `mixin` method. | ||
* @return {Object} | ||
*/ | ||
function defaultMixinMergeStrategy (mergeObject, mixinObject) { | ||
return Object.assign(mixinObject, mergeObject) | ||
} | ||
function write (_obj, msg, num) { | ||
const t = this[timeSym]() | ||
const mixin = this[mixinSym] | ||
const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy | ||
let obj | ||
if (_obj === undefined || _obj === null) { | ||
obj = mixin ? mixin({}) : {} | ||
obj = {} | ||
} else if (_obj instanceof Error) { | ||
obj = Object.assign(mixin ? mixin({}) : {}, { err: _obj }) | ||
obj = { err: _obj } | ||
if (msg === undefined) { | ||
@@ -176,3 +190,3 @@ msg = _obj.message | ||
} else { | ||
obj = Object.assign(mixin ? mixin({}) : {}, _obj) | ||
obj = _obj | ||
if (msg === undefined && _obj.err) { | ||
@@ -183,2 +197,6 @@ msg = _obj.err.message | ||
if (mixin) { | ||
obj = mixinMergeStrategy(obj, mixin(obj, num)) | ||
} | ||
const s = this[asJsonSym](obj, msg, num, t) | ||
@@ -185,0 +203,0 @@ |
@@ -29,2 +29,3 @@ 'use strict' | ||
const nestedKeyStrSym = Symbol('pino.nestedKeyStr') | ||
const mixinMergeStrategySym = Symbol('pino.mixinMergeStrategy') | ||
@@ -68,3 +69,4 @@ const wildcardFirstSym = Symbol('pino.wildcardFirst') | ||
hooksSym, | ||
nestedKeyStrSym | ||
nestedKeyStrSym, | ||
mixinMergeStrategySym | ||
} |
@@ -111,3 +111,2 @@ 'use strict' | ||
let value | ||
const notHasOwnProperty = obj.hasOwnProperty === undefined | ||
if (formatters.log) { | ||
@@ -120,3 +119,3 @@ obj = formatters.log(obj) | ||
value = obj[key] | ||
if ((notHasOwnProperty || obj.hasOwnProperty(key)) && value !== undefined) { | ||
if (Object.prototype.hasOwnProperty.call(obj, key) && value !== undefined) { | ||
value = serializers[key] ? serializers[key](value) : value | ||
@@ -296,3 +295,3 @@ | ||
const messageKey = lastLogger[messageKeySym] | ||
if (lastMsg && formattedObj && !formattedObj.hasOwnProperty(messageKey)) { | ||
if (lastMsg && formattedObj && !Object.prototype.hasOwnProperty.call(formattedObj, messageKey)) { | ||
formattedObj[messageKey] = lastMsg | ||
@@ -415,3 +414,11 @@ } | ||
} | ||
stream = transport({ caller, ...opts.transport }) | ||
if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') { | ||
throw Error('option.transport.targets do not allow custom level formatters') | ||
} | ||
let customLevels | ||
if (opts.customLevels) { | ||
customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels) | ||
} | ||
stream = transport({ caller, ...opts.transport, levels: customLevels }) | ||
} | ||
@@ -418,0 +425,0 @@ opts = Object.assign({}, defaultOptions, opts) |
@@ -6,2 +6,3 @@ 'use strict' | ||
const { join, isAbsolute } = require('path') | ||
const sleep = require('atomic-sleep') | ||
@@ -67,2 +68,7 @@ let onExit | ||
stream.flushSync() | ||
// Apparently there is a very sporadic race condition | ||
// that in certain OS would prevent the messages to be flushed | ||
// because the thread might not have been created still. | ||
// Unfortunately we need to sleep(100) in this case. | ||
sleep(100) | ||
stream.end() | ||
@@ -84,3 +90,3 @@ } | ||
function transport (fullOptions) { | ||
const { pipeline, targets, options = {}, worker = {}, caller = getCallers() } = fullOptions | ||
const { pipeline, targets, levels, options = {}, worker = {}, caller = getCallers() } = fullOptions | ||
@@ -107,3 +113,3 @@ // Backwards compatibility | ||
}) | ||
} else if (fullOptions.pipeline) { | ||
} else if (pipeline) { | ||
target = bundlerOverrides['pino-pipeline-worker'] || join(__dirname, 'worker-pipeline.js') | ||
@@ -118,2 +124,6 @@ options.targets = pipeline.map((dest) => { | ||
if (levels) { | ||
options.levels = levels | ||
} | ||
return buildStream(fixTarget(target), options, worker) | ||
@@ -120,0 +130,0 @@ |
'use strict' | ||
const EE = require('events') | ||
const { realImport, realRequire } = require('real-require') | ||
const loadTransportStreamBuilder = require('./transport-stream') | ||
const { pipeline, PassThrough } = require('stream') | ||
@@ -14,14 +14,3 @@ | ||
const streams = await Promise.all(targets.map(async (t) => { | ||
let fn | ||
try { | ||
const toLoad = 'file://' + t.target | ||
fn = (await realImport(toLoad)).default | ||
} catch (error) { | ||
// See this PR for details: https://github.com/pinojs/thread-stream/pull/34 | ||
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) { | ||
fn = realRequire(t.target) | ||
} else { | ||
throw error | ||
} | ||
} | ||
const fn = await loadTransportStreamBuilder(t.target) | ||
const stream = await fn(t.options) | ||
@@ -28,0 +17,0 @@ return stream |
@@ -5,3 +5,3 @@ 'use strict' | ||
const build = require('pino-abstract-transport') | ||
const { realImport, realRequire } = require('real-require') | ||
const loadTransportStreamBuilder = require('./transport-stream') | ||
@@ -13,16 +13,5 @@ // This file is not checked by the code coverage tool, | ||
module.exports = async function ({ targets }) { | ||
module.exports = async function ({ targets, levels }) { | ||
targets = await Promise.all(targets.map(async (t) => { | ||
let fn | ||
try { | ||
const toLoad = 'file://' + t.target | ||
fn = (await realImport(toLoad)).default | ||
} catch (error) { | ||
// See this PR for details: https://github.com/pinojs/thread-stream/pull/34 | ||
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) { | ||
fn = realRequire(t.target) | ||
} else { | ||
throw error | ||
} | ||
} | ||
const fn = await loadTransportStreamBuilder(t.target) | ||
const stream = await fn(t.options) | ||
@@ -54,3 +43,3 @@ return { | ||
function process (stream) { | ||
const multi = pino.multistream(targets) | ||
const multi = pino.multistream(targets, { levels }) | ||
// TODO manage backpressure | ||
@@ -57,0 +46,0 @@ stream.on('data', function (chunk) { |
{ | ||
"name": "pino", | ||
"version": "7.6.5", | ||
"version": "7.11.0", | ||
"description": "super fast, all natural json logger", | ||
@@ -26,8 +26,9 @@ "main": "pino.js", | ||
"lint": "eslint .", | ||
"test": "npm run lint && tap test/*test.js test/*/*test.js && jest test/jest && npm run test-types", | ||
"test-ci": "npm run lint && tap --no-check-coverage test/*test.js test/*/*test.js --coverage-report=lcovonly && npm run test-types", | ||
"test-ci-pnpm": "pnpm run lint && tap --no-coverage --no-check-coverage test/*test.js test/*/*test.js && pnpm run test-types", | ||
"test-ci-yarn-pnp": "yarn run lint && tap --no-check-coverage test/*test.js test/*/*test.js --coverage-report=lcovonly", | ||
"test": "npm run lint && npm run transpile && tap --ts && jest test/jest && npm run test-types", | ||
"test-ci": "npm run lint && npm run transpile && tap --ts --no-check-coverage --coverage-report=lcovonly && npm run test-types", | ||
"test-ci-pnpm": "pnpm run lint && npm run transpile && tap --ts --no-coverage --no-check-coverage && pnpm run test-types", | ||
"test-ci-yarn-pnp": "yarn run lint && npm run transpile && tap --ts --no-check-coverage --coverage-report=lcovonly", | ||
"test-types": "tsc && tsd && ts-node test/types/pino.ts", | ||
"cov-ui": "tap --coverage-report=html test/*test.js test/*/*test.js", | ||
"transpile": "node ./test/fixtures/ts/transpile.cjs", | ||
"cov-ui": "tap --ts --coverage-report=html", | ||
"bench": "node benchmarks/utils/runbench all", | ||
@@ -71,3 +72,5 @@ "bench-basic": "node benchmarks/utils/runbench basic", | ||
"devDependencies": { | ||
"@types/flush-write-stream": "^1.0.0", | ||
"@types/node": "^17.0.0", | ||
"@types/tap": "^15.0.6", | ||
"airtap": "4.0.4", | ||
@@ -90,6 +93,7 @@ "benchmark": "^2.1.4", | ||
"loglevel": "^1.6.7", | ||
"pino-pretty": "^v7.5.1", | ||
"pino-pretty": "^v7.6.0", | ||
"pre-commit": "^1.2.2", | ||
"proxyquire": "^2.1.3", | ||
"pump": "^3.0.0", | ||
"rimraf": "^3.0.2", | ||
"semver": "^7.0.0", | ||
@@ -99,7 +103,7 @@ "split2": "^4.0.0", | ||
"strip-ansi": "^6.0.0", | ||
"tap": "^15.0.1", | ||
"tap": "^16.0.0", | ||
"tape": "^5.0.0", | ||
"through2": "^4.0.0", | ||
"ts-node": "^10.3.0", | ||
"tsd": "^0.19.0", | ||
"ts-node": "^10.7.0", | ||
"tsd": "^0.20.0", | ||
"typescript": "^4.4.4", | ||
@@ -109,7 +113,8 @@ "winston": "^3.3.3" | ||
"dependencies": { | ||
"atomic-sleep": "^1.0.0", | ||
"fast-redact": "^3.0.0", | ||
"process-warning": "^1.0.0", | ||
"on-exit-leak-free": "^0.2.0", | ||
"pino-abstract-transport": "v0.5.0", | ||
"pino-std-serializers": "^4.0.0", | ||
"process-warning": "^1.0.0", | ||
"quick-format-unescaped": "^4.0.3", | ||
@@ -119,3 +124,3 @@ "real-require": "^0.1.0", | ||
"sonic-boom": "^2.2.1", | ||
"thread-stream": "^0.13.0" | ||
"thread-stream": "^0.15.1" | ||
}, | ||
@@ -122,0 +127,0 @@ "tsd": { |
@@ -34,3 +34,4 @@ // Type definitions for pino 7.0 | ||
type TimeFn = () => string; | ||
type MixinFn = () => object; | ||
type MixinFn = (mergeObject: object, level: number) => object; | ||
type MixinMergeStrategyFn = (mergeObject: object, mixinObject: object) => object; | ||
@@ -41,3 +42,3 @@ type CustomLevelLogger<Options> = Options extends { customLevels: Record<string, number> } ? Record<keyof Options["customLevels"], LogFn> : Record<never, LogFn> | ||
paths: string[]; | ||
censor?: string | ((v: any) => any); | ||
censor?: string | ((value: any, path: string[]) => any); | ||
remove?: boolean; | ||
@@ -107,2 +108,14 @@ } | ||
bindings(): pino.Bindings; | ||
/** | ||
* Overwrites the bindings of this logger instance. | ||
* | ||
* @param bindings: an object of key-value pairs to include in log lines as properties. | ||
*/ | ||
setBindings(bindings: pino.Bindings): void; | ||
/** | ||
* Flushes the content of the buffer when using pino.destination({ sync: false }). | ||
*/ | ||
flush(): () => void; | ||
} | ||
@@ -113,3 +126,3 @@ | ||
//// Exported types and interfaces | ||
interface BaseLogger { | ||
@@ -132,3 +145,3 @@ /** | ||
level: pino.LevelWithSilent | string; | ||
/** | ||
@@ -207,3 +220,3 @@ * Log at `'fatal'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line. | ||
type WriteFn = (o: object) => void; | ||
type LevelChangeEventListener = ( | ||
@@ -215,3 +228,3 @@ lvl: LevelWithSilent | string, | ||
) => void; | ||
type LogDescriptor = Record<string, any>; | ||
@@ -229,3 +242,3 @@ | ||
options: TransportOptions | ||
level: LevelWithSilent | ||
level: LevelWithSilent | string | ||
} | ||
@@ -247,3 +260,4 @@ | ||
interface TransportMultiOptions<TransportOptions = Record<string, any>> extends TransportBaseOptions<TransportOptions>{ | ||
targets: readonly TransportTargetOptions<TransportOptions>[] | ||
targets: readonly TransportTargetOptions<TransportOptions>[], | ||
levels?: Record<string, number> | ||
} | ||
@@ -267,6 +281,6 @@ | ||
write: (data: any) => void, | ||
add: (dest: Record<string, any>) => MultiStreamRes, | ||
add: (dest: StreamEntry | DestinationStream) => MultiStreamRes, | ||
flushSync: () => void, | ||
minLevel: number, | ||
streams: ({ stream: DestinationStream, level: number, id: number })[], | ||
streams: StreamEntry[], | ||
clone(level: Level): MultiStreamRes, | ||
@@ -345,2 +359,10 @@ } | ||
/** | ||
* If provided, the `mixinMergeStrategy` function is called each time one of the active | ||
* logging methods is called. The first parameter is the value `mergeObject` or an empty object, | ||
* the second parameter is the value resulting from `mixin()` or an empty object. | ||
* The function must synchronously return an object. | ||
*/ | ||
mixinMergeStrategy?: MixinMergeStrategyFn | ||
/** | ||
* As an array, the redact option specifies paths that should have their values redacted from any log output. | ||
@@ -680,3 +702,3 @@ * | ||
}; | ||
/** | ||
@@ -686,3 +708,3 @@ * Exposes the Pino package version. Also available on the logger instance. | ||
export const version: string; | ||
/** | ||
@@ -712,3 +734,3 @@ * Provides functions for generating the timestamp property in the log output. You can set the `timestamp` option during | ||
}; | ||
//// Exported functions | ||
@@ -767,4 +789,4 @@ | ||
declare function pino<Options extends LoggerOptions>(options: Options, stream: DestinationStream): Logger<Options>; | ||
// Pass through all the top-level exports, allows `import {version} from "pino"` | ||
@@ -785,2 +807,3 @@ // Constants and functions | ||
export type Level = pino.Level; | ||
export type LevelWithSilent = pino.LevelWithSilent; | ||
export type LevelChangeEventListener = pino.LevelChangeEventListener; | ||
@@ -787,0 +810,0 @@ export type LogDescriptor = pino.LogDescriptor; |
@@ -11,3 +11,3 @@ 'use strict' | ||
const { configure } = require('safe-stable-stringify') | ||
const { assertDefaultLevelFound, mappings, genLsCache } = require('./lib/levels') | ||
const { assertDefaultLevelFound, mappings, genLsCache, levels } = require('./lib/levels') | ||
const { | ||
@@ -43,3 +43,4 @@ createArgsNormalizer, | ||
hooksSym, | ||
nestedKeyStrSym | ||
nestedKeyStrSym, | ||
mixinMergeStrategySym | ||
} = symbols | ||
@@ -52,2 +53,3 @@ const { epochTime, nullTime } = time | ||
level: 'info', | ||
levels, | ||
messageKey: 'msg', | ||
@@ -100,2 +102,3 @@ nestedKey: null, | ||
mixin, | ||
mixinMergeStrategy, | ||
useOnlyCustomLevels, | ||
@@ -173,2 +176,3 @@ formatters, | ||
[mixinSym]: mixin, | ||
[mixinMergeStrategySym]: mixinMergeStrategy, | ||
[chindingsSym]: chindings, | ||
@@ -175,0 +179,0 @@ [formattersSym]: allFormatters, |
@@ -23,3 +23,2 @@ ![banner](pino-banner.png) | ||
* [Ecosystem ⇗](/docs/ecosystem.md) | ||
* [Legacy](/docs/legacy.md) | ||
* [Help ⇗](/docs/help.md) | ||
@@ -26,0 +25,0 @@ * [Long Term Support Policy ⇗](/docs/lts.md) |
'use strict' | ||
const os = require('os') | ||
const { join } = require('path') | ||
const { readFileSync } = require('fs') | ||
const { test } = require('tap') | ||
const { sink, check, once, watchFileCreated } = require('./helper') | ||
const { sink, check, once, watchFileCreated, file } = require('./helper') | ||
const pino = require('../') | ||
@@ -514,6 +513,3 @@ const { version } = require('../package.json') | ||
test('pino.destination', async ({ same }) => { | ||
const tmp = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const tmp = file() | ||
const instance = pino(pino.destination(tmp)) | ||
@@ -533,6 +529,3 @@ instance.info('hello') | ||
test('auto pino.destination with a string', async ({ same }) => { | ||
const tmp = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const tmp = file() | ||
const instance = pino(tmp) | ||
@@ -552,6 +545,3 @@ instance.info('hello') | ||
test('auto pino.destination with a string as second argument', async ({ same }) => { | ||
const tmp = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const tmp = file() | ||
const instance = pino(null, tmp) | ||
@@ -571,6 +561,3 @@ instance.info('hello') | ||
test('does not override opts with a string as second argument', async ({ same }) => { | ||
const tmp = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const tmp = file() | ||
const instance = pino({ | ||
@@ -577,0 +564,0 @@ timestamp: () => ',"time":"none"' |
@@ -8,3 +8,3 @@ /* eslint-disable no-eval */ | ||
pino.transport({ | ||
target: 'pino-pretty' | ||
target: 'pino/file' | ||
}) | ||
@@ -11,0 +11,0 @@ ) |
@@ -6,3 +6,3 @@ const pino = require("../../../../"); | ||
pino.transport({ | ||
target: 'pino-pretty' | ||
target: 'pino/file' | ||
}) | ||
@@ -9,0 +9,0 @@ ) |
'use strict' | ||
/* eslint no-prototype-builtins: 0 */ | ||
const os = require('os') | ||
const { hostname } = require('os') | ||
@@ -9,3 +8,3 @@ const { join } = require('path') | ||
const { test } = require('tap') | ||
const { sink, once, watchFileCreated } = require('./helper') | ||
const { sink, once, watchFileCreated, file } = require('./helper') | ||
const pino = require('../') | ||
@@ -308,6 +307,3 @@ | ||
test('formatter with transport', async ({ match, equal }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const logger = pino({ | ||
@@ -340,1 +336,23 @@ formatters: { | ||
}) | ||
test('throws when custom level formatter is used with transport.targets', async ({ throws }) => { | ||
throws(() => { | ||
pino({ | ||
formatters: { | ||
level (label) { | ||
return label | ||
} | ||
}, | ||
transport: { | ||
targets: [ | ||
{ | ||
target: 'pino/file', | ||
options: { destination: 'foo.log' } | ||
} | ||
] | ||
} | ||
} | ||
) | ||
}, | ||
Error('option.transport.targets do not allow custom level formatters')) | ||
}) |
'use strict' | ||
const crypto = require('crypto') | ||
const os = require('os') | ||
const writer = require('flush-write-stream') | ||
const split = require('split2') | ||
const { existsSync, readFileSync, statSync } = require('fs') | ||
const { existsSync, readFileSync, statSync, unlinkSync } = require('fs') | ||
const pid = process.pid | ||
const hostname = os.hostname() | ||
const t = require('tap') | ||
const { join } = require('path') | ||
const { tmpdir } = os | ||
@@ -100,2 +104,26 @@ const isWin = process.platform === 'win32' | ||
module.exports = { getPathToNull, sink, check, once, sleep, watchFileCreated, watchForWrite, isWin, isYarnPnp } | ||
let files = [] | ||
function file () { | ||
const hash = crypto.randomBytes(12).toString('hex') | ||
const file = join(tmpdir(), `pino-${pid}-${hash}`) | ||
files.push(file) | ||
return file | ||
} | ||
process.on('beforeExit', () => { | ||
if (files.length === 0) return | ||
t.comment('unlink files') | ||
for (const file of files) { | ||
try { | ||
t.comment(`unliking ${file}`) | ||
unlinkSync(file) | ||
} catch (e) { | ||
console.log(e) | ||
} | ||
} | ||
files = [] | ||
t.comment('unlink completed') | ||
}) | ||
module.exports = { getPathToNull, sink, check, once, sleep, watchFileCreated, watchForWrite, isWin, isYarnPnp, file } |
@@ -105,3 +105,3 @@ 'use strict' | ||
test('mixin can use context', async ({ ok }) => { | ||
test('mixin can use context', async ({ ok, same }) => { | ||
const stream = sink() | ||
@@ -112,2 +112,6 @@ const instance = pino({ | ||
ok(context !== undefined, 'context should be defined') | ||
same(context, { | ||
message: '123', | ||
stack: 'stack' | ||
}) | ||
return Object.assign({ | ||
@@ -126,3 +130,3 @@ error: context.message, | ||
test('mixin works without context', async ({ ok }) => { | ||
test('mixin works without context', async ({ ok, same }) => { | ||
const stream = sink() | ||
@@ -133,2 +137,3 @@ const instance = pino({ | ||
ok(context !== undefined, 'context is still defined w/o passing mergeObject') | ||
same(context, {}) | ||
return { | ||
@@ -142,1 +147,21 @@ something: true | ||
}) | ||
test('mixin can use level number', async ({ ok, same }) => { | ||
const stream = sink() | ||
const instance = pino({ | ||
mixin (context, num) { | ||
ok(num !== null, 'level should be defined') | ||
ok(num !== undefined, 'level should be defined') | ||
same(num, level) | ||
return Object.assign({ | ||
error: context.message, | ||
stack: context.stack | ||
}) | ||
} | ||
}, stream) | ||
instance.level = name | ||
instance[name]({ | ||
message: '123', | ||
stack: 'stack' | ||
}, 'test') | ||
}) |
'use strict' | ||
const writeStream = require('flush-write-stream') | ||
const { join } = require('path') | ||
const { readFileSync } = require('fs') | ||
const os = require('os') | ||
const test = require('tap').test | ||
@@ -12,2 +10,3 @@ const pino = require('../') | ||
const strip = require('strip-ansi') | ||
const { file } = require('./helper') | ||
@@ -225,8 +224,13 @@ test('sends to multiple streams using string levels', function (t) { | ||
const pretty = proxyquire('pino-pretty', { | ||
const nested = proxyquire('pino-pretty/lib/utils', { | ||
'sonic-boom': function () { | ||
t.pass('sonic created') | ||
stream.flushSync = () => {} | ||
stream.flush = () => {} | ||
return stream | ||
} | ||
}) | ||
const pretty = proxyquire('pino-pretty', { | ||
'./lib/utils': nested | ||
}) | ||
@@ -486,3 +490,3 @@ const log = pino({ | ||
test('add a stream', function (t) { | ||
test('one stream', function (t) { | ||
let messageCount = 0 | ||
@@ -503,7 +507,41 @@ const stream = writeStream(function (data, enc, cb) { | ||
test('add a stream', function (t) { | ||
let messageCount = 0 | ||
const stream = writeStream(function (data, enc, cb) { | ||
messageCount += 1 | ||
cb() | ||
}) | ||
const log = pino({ | ||
level: 'trace' | ||
}, multistream().add(stream)) | ||
log.info('info stream') | ||
log.debug('debug stream') | ||
log.fatal('fatal stream') | ||
t.equal(messageCount, 2) | ||
t.end() | ||
}) | ||
test('multistream.add throws if not a stream', function (t) { | ||
try { | ||
pino({ | ||
level: 'trace' | ||
}, multistream().add({})) | ||
} catch (_) { | ||
t.end() | ||
} | ||
}) | ||
test('multistream throws if not a stream', function (t) { | ||
try { | ||
pino({ | ||
level: 'trace' | ||
}, multistream({})) | ||
} catch (_) { | ||
t.end() | ||
} | ||
}) | ||
test('flushSync', function (t) { | ||
const tmp = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const tmp = file() | ||
const destination = pino.destination({ dest: tmp, sync: false, minLength: 4096 }) | ||
@@ -510,0 +548,0 @@ const log = pino({ level: 'info' }, multistream([{ level: 'info', stream: destination }])) |
@@ -344,2 +344,14 @@ 'use strict' | ||
test('handles objects with null prototypes', async ({ not }) => { | ||
let actual = '' | ||
const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'pretty', 'null-prototype.js')]) | ||
child.stdout.pipe(writer((s, enc, cb) => { | ||
actual += s | ||
cb() | ||
})) | ||
await once(child, 'close') | ||
not(strip(actual).match(/\(123456 on abcdefghijklmnopqr\): hello\s+foo: "bar"/), null) | ||
}) | ||
test('should not lose stream metadata for streams with `needsMetadataGsym` flag', async ({ not }) => { | ||
@@ -346,0 +358,0 @@ const dest = new Writable({ |
@@ -5,5 +5,3 @@ 'use strict' | ||
const { join } = require('path') | ||
const { once } = require('events') | ||
const { createReadStream } = require('fs') | ||
const os = require('os') | ||
const { promisify } = require('util') | ||
@@ -13,14 +11,21 @@ const execa = require('execa') | ||
const stream = require('stream') | ||
const { file } = require('../helper') | ||
const pipeline = promisify(stream.pipeline) | ||
const { Writable } = stream | ||
const sleep = promisify(setTimeout) | ||
test('eight million lines', async ({ equal, comment }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-many-lines.js'), destination]) | ||
const destination = file() | ||
await execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-many-lines.js'), destination]) | ||
await once(child, 'exit') | ||
if (process.platform !== 'win32') { | ||
try { | ||
await execa('sync') // Wait for the file to be writen to disk | ||
} catch { | ||
// Just a fallback, this should be unreachable | ||
} | ||
} | ||
await sleep(1000) // It seems that sync is not enough (even in POSIX systems) | ||
const toWrite = 8 * 1000000 | ||
@@ -27,0 +32,0 @@ let count = 0 |
@@ -6,3 +6,3 @@ 'use strict' | ||
const { readFile } = require('fs').promises | ||
const { watchFileCreated } = require('../helper') | ||
const { watchFileCreated, file } = require('../helper') | ||
const { test } = require('tap') | ||
@@ -19,6 +19,3 @@ const pino = require('../../pino') | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -49,6 +46,3 @@ target: 'foobar', | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -83,6 +77,3 @@ targets: [ | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -89,0 +80,0 @@ pipeline: [ |
'use strict' | ||
const writer = require('flush-write-stream') | ||
const { join } = require('path') | ||
@@ -8,17 +7,6 @@ const { test } = require('tap') | ||
const { once } = require('../helper') | ||
test('when using a custom transport outside node_modules, the first file outside node_modules should be used', async function (t) { | ||
const evalApp = join(__dirname, '../', '/fixtures/eval/index.js') | ||
const child = execa(process.argv[0], [evalApp]) | ||
let actual = '' | ||
child.stdout.pipe(writer((s, enc, cb) => { | ||
actual += s | ||
cb() | ||
})) | ||
await once(child, 'close') | ||
t.match(actual, /done!/) | ||
const { stdout } = await execa(process.argv[0], [evalApp]) | ||
t.match(stdout, /done!/) | ||
}) | ||
@@ -28,13 +16,4 @@ | ||
const evalApp = join(__dirname, '../', '/fixtures/eval/node_modules/2-files.js') | ||
const child = execa(process.argv[0], [evalApp]) | ||
let actual = '' | ||
child.stdout.pipe(writer((s, enc, cb) => { | ||
actual += s | ||
cb() | ||
})) | ||
await once(child, 'close') | ||
t.match(actual, /done!/) | ||
const { stdout } = await execa(process.argv[0], [evalApp]) | ||
t.match(stdout, /done!/) | ||
}) | ||
@@ -44,13 +23,4 @@ | ||
const evalApp = join(__dirname, '../', '/fixtures/eval/node_modules/14-files.js') | ||
const child = execa(process.argv[0], [evalApp]) | ||
let actual = '' | ||
child.stdout.pipe(writer((s, enc, cb) => { | ||
actual += s | ||
cb() | ||
})) | ||
await once(child, 'close') | ||
t.match(actual, /done!/) | ||
const { stdout } = await execa(process.argv[0], [evalApp]) | ||
t.match(stdout, /done!/) | ||
}) |
@@ -7,3 +7,3 @@ 'use strict' | ||
const { readFile, writeFile } = require('fs').promises | ||
const { watchFileCreated, watchForWrite } = require('../helper') | ||
const { watchFileCreated, watchForWrite, file } = require('../helper') | ||
const { test } = require('tap') | ||
@@ -15,11 +15,10 @@ const pino = require('../../') | ||
const writer = require('flush-write-stream') | ||
const rimraf = require('rimraf') | ||
const { tmpdir } = os | ||
const { pid } = process | ||
const pid = process.pid | ||
const hostname = os.hostname() | ||
test('pino.transport with file', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -52,6 +51,3 @@ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'), | ||
test('pino.transport with file URL', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -90,7 +86,30 @@ target: url.pathToFileURL(join(__dirname, '..', 'fixtures', 'to-file-transport.js')).href, | ||
test('pino.transport errors if transport worker module does not export a function', ({ plan, equal }) => { | ||
// TODO: add case for non-pipelined single target (needs changes in thread-stream) | ||
plan(2) | ||
const manyTargetsInstance = pino.transport({ | ||
targets: [{ | ||
level: 'info', | ||
target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js') | ||
}, { | ||
level: 'info', | ||
target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js') | ||
}] | ||
}) | ||
manyTargetsInstance.on('error', function (e) { | ||
equal(e.message, 'exported worker is not a function') | ||
}) | ||
const pipelinedInstance = pino.transport({ | ||
pipeline: [{ | ||
target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js') | ||
}] | ||
}) | ||
pipelinedInstance.on('error', function (e) { | ||
equal(e.message, 'exported worker is not a function') | ||
}) | ||
}) | ||
test('pino.transport with esm', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -115,10 +134,4 @@ target: join(__dirname, '..', 'fixtures', 'to-file-transport.mjs'), | ||
test('pino.transport with two files', async ({ same, teardown }) => { | ||
const dest1 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest2 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest1 = file() | ||
const dest2 = file() | ||
const transport = pino.transport({ | ||
@@ -157,11 +170,42 @@ targets: [{ | ||
test('pino.transport with two files and custom levels', async ({ same, teardown }) => { | ||
const dest1 = file() | ||
const dest2 = file() | ||
const transport = pino.transport({ | ||
targets: [{ | ||
level: 'info', | ||
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'), | ||
options: { destination: dest1 } | ||
}, { | ||
level: 'foo', | ||
target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'), | ||
options: { destination: dest2 } | ||
}], | ||
levels: { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, foo: 25 } | ||
}) | ||
teardown(transport.end.bind(transport)) | ||
const instance = pino(transport) | ||
instance.info('hello') | ||
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: 30, | ||
msg: 'hello' | ||
}) | ||
}) | ||
test('pino.transport with an array including a pino-pretty destination', async ({ same, match, teardown }) => { | ||
const dest1 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest2 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest1 = file() | ||
const dest2 = file() | ||
const transport = pino.transport({ | ||
@@ -199,6 +243,3 @@ targets: [{ | ||
test('no transport.end()', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -222,6 +263,3 @@ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'), | ||
test('autoEnd = false', async ({ equal, same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const count = process.listenerCount('exit') | ||
@@ -268,6 +306,3 @@ const transport = pino.transport({ | ||
test('pino.transport with target pino/file', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -292,4 +327,11 @@ target: 'pino/file', | ||
test('pino.transport with target pino/file and mkdir option', async ({ same, teardown }) => { | ||
const folder = '_' + Math.random().toString(36).substr(2, 9) | ||
const destination = join(os.tmpdir(), folder, folder) | ||
const folder = join(tmpdir(), `pino-${process.pid}-mkdir-transport-file`) | ||
const destination = join(folder, 'log.txt') | ||
teardown(() => { | ||
try { | ||
rimraf.sync(folder) | ||
} catch (err) { | ||
// ignore | ||
} | ||
}) | ||
const transport = pino.transport({ | ||
@@ -314,6 +356,3 @@ target: 'pino/file', | ||
test('pino.transport with target pino/file and append option', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
await writeFile(destination, JSON.stringify({ pid, hostname, time: Date.now(), level: 30, msg: 'hello' })) | ||
@@ -351,6 +390,3 @@ const transport = pino.transport({ | ||
test('pino.transport with target pino-pretty', async ({ match, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -405,6 +441,3 @@ target: 'pino-pretty', | ||
test('log and exit before ready with async dest', async ({ not }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-exit-immediately-with-async-dest.js'), destination]) | ||
@@ -432,6 +465,3 @@ | ||
test('pino transport options with target', async ({ teardown, same }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const instance = pino({ | ||
@@ -458,10 +488,4 @@ transport: { | ||
test('pino transport options with targets', async ({ teardown, same }) => { | ||
const dest1 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest2 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest1 = file() | ||
const dest2 = file() | ||
const instance = pino({ | ||
@@ -527,6 +551,3 @@ transport: { | ||
try { | ||
const dest1 = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const dest1 = file() | ||
const transportStream = pino.transport({ target: 'pino/file', options: { destination: dest1 } }) | ||
@@ -533,0 +554,0 @@ teardown(transportStream.end.bind(transportStream)) |
@@ -7,6 +7,7 @@ 'use strict' | ||
const { test } = require('tap') | ||
const { isWin, isYarnPnp, watchFileCreated } = require('../helper') | ||
const { isWin, isYarnPnp, watchFileCreated, file } = require('../helper') | ||
const { once } = require('events') | ||
const execa = require('execa') | ||
const pino = require('../../') | ||
const rimraf = require('rimraf') | ||
@@ -43,6 +44,3 @@ const { pid } = process | ||
test('pino.transport with package', { skip: isWin }, async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
@@ -75,6 +73,3 @@ await installTransportModule() | ||
test('pino.transport with package as a target', { skip: isWin }, async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
@@ -113,2 +108,6 @@ await installTransportModule() | ||
teardown(() => { | ||
rimraf.sync(folder) | ||
}) | ||
const destination = join(folder, 'output') | ||
@@ -156,3 +155,3 @@ | ||
// TODO make this test pass on Windows | ||
test('pino({ transport }) from a wrapped dependency', { skip: isWin || isYarnPnp, only: true }, async ({ same, teardown }) => { | ||
test('pino({ transport }) from a wrapped dependency', { skip: isWin || isYarnPnp }, async ({ same, teardown }) => { | ||
const folder = join( | ||
@@ -173,2 +172,7 @@ os.tmpdir(), | ||
teardown(() => { | ||
rimraf.sync(wrappedFolder) | ||
rimraf.sync(folder) | ||
}) | ||
// Link pino | ||
@@ -175,0 +179,0 @@ await symlink( |
@@ -6,3 +6,3 @@ 'use strict' | ||
const { readFile } = require('fs').promises | ||
const { watchFileCreated } = require('../helper') | ||
const { watchFileCreated, file } = require('../helper') | ||
const { test } = require('tap') | ||
@@ -15,6 +15,3 @@ const pino = require('../../') | ||
test('pino.transport with a pipeline', async ({ same, teardown }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -21,0 +18,0 @@ pipeline: [{ |
@@ -8,3 +8,3 @@ 'use strict' | ||
const { readFile } = require('fs').promises | ||
const { watchFileCreated } = require('../helper') | ||
const { watchFileCreated, file } = require('../helper') | ||
@@ -15,6 +15,3 @@ const { pid } = process | ||
test('thread-stream async flush', async ({ same }) => { | ||
const destination = join( | ||
os.tmpdir(), | ||
'_' + Math.random().toString(36).substr(2, 9) | ||
) | ||
const destination = file() | ||
const transport = pino.transport({ | ||
@@ -21,0 +18,0 @@ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'), |
@@ -24,3 +24,4 @@ import { expectType } from 'tsd' | ||
expectType<pino.MultiStreamRes>(pino.multistream(streams, { dedupe: true })) | ||
expectType<pino.MultiStreamRes>(pino.multistream(streams[0]).add(streams[1])) | ||
expectType<pino.MultiStreamRes>(multistream(process.stdout)); |
@@ -47,3 +47,32 @@ import { pino } from '../../pino' | ||
const transportsWithCustomLevels = pino.transport({targets: [ | ||
{ | ||
level: 'info', | ||
target: '#pino/pretty', | ||
options: { some: 'options for', the: 'transport' } | ||
}, | ||
{ | ||
level: 'foo', | ||
target: '#pino/file', | ||
options: { destination: './test.log' } | ||
} | ||
], levels: { foo: 35 }}) | ||
pino(transports) | ||
expectType<pino.Logger>(pino({ | ||
transport: {targets: [ | ||
{ | ||
level: 'info', | ||
target: '#pino/pretty', | ||
options: { some: 'options for', the: 'transport' } | ||
}, | ||
{ | ||
level: 'trace', | ||
target: '#pino/file', | ||
options: { destination: './test.log' } | ||
} | ||
], levels: { foo: 35 } | ||
}, | ||
})) | ||
const pipelineTransport = pino.transport({ | ||
@@ -50,0 +79,0 @@ pipeline: [{ |
@@ -1,5 +0,5 @@ | ||
import { expectType } from "tsd"; | ||
import { expectAssignable, expectType } from "tsd"; | ||
import pino from "../../"; | ||
import type {Logger, LogFn, P} from "../../pino"; | ||
import type {LevelWithSilent, Logger, LogFn, P} from "../../pino"; | ||
@@ -13,2 +13,5 @@ // NB: can also use `import * as pino`, but that form is callable as `pino()` | ||
expectType<P.Logger>(log); | ||
expectType<P.LogFn>(log.info); | ||
expectType<P.LogFn>(log.info); | ||
const level: LevelWithSilent = 'silent'; | ||
expectAssignable<P.LevelWithSilent>(level); |
@@ -51,2 +51,10 @@ import P, { pino } from "../../"; | ||
pino({ | ||
mixin: (context: object) => ({ customName: "unknown", customId: 111 }), | ||
}); | ||
pino({ | ||
mixin: (context: object, level: number) => ({ customName: "unknown", customId: 111 }), | ||
}); | ||
pino({ | ||
redact: { paths: [], censor: "SECRET" }, | ||
@@ -60,2 +68,10 @@ }); | ||
pino({ | ||
redact: { paths: [], censor: (value) => value }, | ||
}); | ||
pino({ | ||
redact: { paths: [], censor: (value, path) => path.join() }, | ||
}); | ||
pino({ | ||
depthLimit: 1 | ||
@@ -62,0 +78,0 @@ }); |
import { pino } from '../../pino' | ||
import { join } from 'path' | ||
import { tmpdir } from'os' | ||
import { tmpdir } from 'os' | ||
@@ -16,3 +16,5 @@ const destination = join( | ||
const logger = pino(transport) | ||
logger.setBindings({ some: 'bindings' }) | ||
logger.info('test2') | ||
logger.flush() | ||
@@ -19,0 +21,0 @@ const transport2 = pino.transport({ |
Sorry, the diff of this file is not supported yet
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
493099
164
11962
11
36
156
57
+ Addedatomic-sleep@^1.0.0
+ Addedthread-stream@0.15.2(transitive)
- Removedthread-stream@0.13.2(transitive)
Updatedthread-stream@^0.15.1