Skip to content

Commit

Permalink
feat: child redact option (#1059)
Browse files Browse the repository at this point in the history
  • Loading branch information
climba03003 authored Jul 10, 2021
1 parent 43d319a commit 7567aad
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
22 changes: 21 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ logger.info('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-redact"></a>
#### `redact` (Array | Object):

Default: `undefined`
Expand Down Expand Up @@ -639,7 +640,7 @@ the process crashes or exits.
Noop function.

<a id="child"></a>
### `logger.child(bindings) => logger`
### `logger.child(bindings, [options]) => logger`

The `logger.child` method allows for the creation of stateful loggers,
where key-value pairs can be pinned to a logger causing them to be output
Expand Down Expand Up @@ -698,6 +699,25 @@ child.info({test: 'will be overwritten'})
* See [`serializers` option](#opt-serializers)
* See [pino.stdSerializers](#pino-stdSerializers)

#### `options` (Object)

Options for child logger. These options will override the parent logger options.

##### `options.redact` (Array | Object)

Setting `options.redact` to an array or object will override the parent `redact` options. To remove `redact` options inherited from the parent logger set this value as an empty array (`[]`).

```js
const logger = require('pino')({ redact: ['hello'] })
logger.info({ hello: 'world' })
// {"level":30,"time":1625794363403,"pid":67930,"hostname":"x","hello":"[Redacted]"}
const child = logger.child({ foo: 'bar' }, { redact: ['foo'] })
logger.info({ hello: 'world' })
// {"level":30,"time":1625794553558,"pid":67930,"hostname":"x","hello":"world", "foo": "[Redacted]" }
```

* See [`redact` option](#opt-redact)

<a id="bindings"></a>
### `logger.bindings()`

Expand Down
26 changes: 23 additions & 3 deletions lib/proto.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ const {
serializersSym,
formattersSym,
useOnlyCustomLevelsSym,
needsMetadataGsym
needsMetadataGsym,
redactFmtSym,
stringifySym,
formatOptsSym,
stringifiersSym
} = require('./symbols')
const {
getLevel,
Expand All @@ -35,11 +39,13 @@ const {
const {
asChindings,
asJson,
buildFormatters
buildFormatters,
stringify
} = require('./tools')
const {
version
} = require('./meta')
const redaction = require('./redaction')

// note: use of class is satirical
// https://github.com/pinojs/pino/pull/433#pullrequestreview-127703127
Expand Down Expand Up @@ -71,10 +77,13 @@ module.exports = function () {
}

const resetChildingsFormatter = bindings => bindings
function child (bindings) {
// TODO: formatters, serializers, customLevels should move to options
// and depercation warning should emit
function child (bindings, options) {
if (!bindings) {
throw Error('missing bindings for child Pino')
}
options = options || {} // default options to empty object
const serializers = this[serializersSym]
const formatters = this[formattersSym]
const instance = Object.create(this)
Expand Down Expand Up @@ -119,6 +128,17 @@ function child (bindings) {
instance.levels = mappings(bindings.customLevels, instance[useOnlyCustomLevelsSym])
genLsCache(instance)
}

// redact must place before asChindings and only replace if exist
if ((typeof options.redact === 'object' && options.redact !== null) || Array.isArray(options.redact)) {
instance.redact = options.redact // replace redact directly
const stringifiers = redaction(instance.redact, stringify)
const formatOpts = { stringify: stringifiers[redactFmtSym] }
instance[stringifySym] = stringify
instance[stringifiersSym] = stringifiers
instance[formatOptsSym] = formatOpts
}

instance[chindingsSym] = asChindings(instance, bindings)
const childLevel = bindings.level || this.level
instance[setLevelSym](childLevel)
Expand Down
39 changes: 39 additions & 0 deletions test/redact.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -775,3 +775,42 @@ test('child bindings are redacted using wildcard and plain path keys', async ({
equal(req.headers.cookie, '[Redacted]')
equal(req.method, '[Redacted]')
})

test('child can customize redact', async ({ equal }) => {
const stream = sink()
const instance = pino({ redact: ['req.method', '*.headers.cookie'] }, stream)
instance.child({
req: {
method: 'GET',
url: '/',
headers: {
cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'
}
}
}, {
redact: ['req.url']
}).info('message completed')
const { req } = await once(stream, 'data')
equal(req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
equal(req.method, 'GET')
equal(req.url, '[Redacted]')
})

test('child can remove parent redact by array', async ({ equal }) => {
const stream = sink()
const instance = pino({ redact: ['req.method', '*.headers.cookie'] }, stream)
instance.child({
req: {
method: 'GET',
url: '/',
headers: {
cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'
}
}
}, {
redact: []
}).info('message completed')
const { req } = await once(stream, 'data')
equal(req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
equal(req.method, 'GET')
})

0 comments on commit 7567aad

Please sign in to comment.