diff --git a/README.md b/README.md index 577bb63..b0933c9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,9 @@ Use the following standardised logging fields to benefit from customised seriali - `req` for HTTP requests. - The request object is trimmed to a set of essential fields. + The request object is trimmed to a set of essential fields. + Certain headers are omitted by default (e.g. `x-envoy-peer-metadata`). + To opt out of this behavior, set the `omitHeaderNames` logger option to an empty list `[]`. - `res` for HTTP responses. diff --git a/src/index.test.ts b/src/index.test.ts index 3c9b285..0b6eca9 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -574,12 +574,25 @@ testLog( ...objectWithDefaultOmitHeaderNameKeys, ['x-request-id']: 'some-uuid', }, + req: { + headers: { + ['authorization']: bearerToken, + ...objectWithDefaultOmitHeaderNameKeys, + ['x-request-id']: 'some-uuid', + }, + }, }, { headers: { ['authorization']: redactedBearer, ['x-request-id']: 'some-uuid', }, + req: { + headers: { + ['authorization']: redactedBearer, + ['x-request-id']: 'some-uuid', + }, + }, }, 'info', ); @@ -592,6 +605,13 @@ testLog( ...objectWithDefaultOmitHeaderNameKeys, ['x-request-id']: 'some-uuid', }, + req: { + headers: { + ['authorization']: bearerToken, + ...objectWithDefaultOmitHeaderNameKeys, + ['x-request-id']: 'some-uuid', + }, + }, }, { headers: { @@ -599,6 +619,13 @@ testLog( ...objectWithDefaultOmitHeaderNameKeys, ['x-request-id']: 'some-uuid', }, + req: { + headers: { + ['authorization']: redactedBearer, + ...objectWithDefaultOmitHeaderNameKeys, + ['x-request-id']: 'some-uuid', + }, + }, }, 'info', { omitHeaderNames: [] }, diff --git a/src/index.ts b/src/index.ts index f7c77e8..3087493 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,11 +4,7 @@ import base from './base'; import { withRedaction } from './destination'; import { type FormatterOptions, createFormatters } from './formatters'; import * as redact from './redact'; -import defaultSerializers, { - type SerializerOptions, - defaultOmitHeaderNames, -} from './serializers'; -import { createOmitPropertiesSerializer } from './serializers/omitPropertiesSerializer'; +import { type SerializerOptions, createSerializers } from './serializers'; export { pino }; @@ -31,14 +27,7 @@ export default ( }), ): Logger => { opts.redact = redact.addDefaultRedactPathStrings(opts.redact); - const omitHeaderNamesSerializer = createOmitPropertiesSerializer('headers', { - omitPropertyNames: opts.omitHeaderNames ?? defaultOmitHeaderNames, - }); - opts.serializers = { - ...defaultSerializers, - ...omitHeaderNamesSerializer, - ...opts.serializers, - }; + opts.serializers = createSerializers(opts); const formatters = createFormatters(opts); opts.base = { ...base, diff --git a/src/serializers/index.test.ts b/src/serializers/index.test.ts index 6bc725e..c7e681e 100644 --- a/src/serializers/index.test.ts +++ b/src/serializers/index.test.ts @@ -1,4 +1,4 @@ -import serializers from './index'; +import serializers, { type Request, defaultOmitHeaderNames } from './index'; describe('req', () => { const remoteAddress = '::ffff:123.45.67.89'; @@ -88,6 +88,23 @@ describe('req', () => { expect(result).toStrictEqual({ ...expectedRequestBase }); }); + + it('omits defaultOmitHeaderNames by default', () => { + const objectWithDefaultOmitHeaderNameKeys = defaultOmitHeaderNames.reduce( + (headers, key) => ({ ...headers, [key]: 'header value' }), + {}, + ); + const request = { + ...requestBase, + headers: { + ...requestBase.headers, + ...objectWithDefaultOmitHeaderNameKeys, + }, + } as Partial as Request; + const result = serializers.req(request); + + expect(result).toStrictEqual({ ...expectedRequestBase }); + }); }); describe('res', () => { diff --git a/src/serializers/index.ts b/src/serializers/index.ts index eafcb76..b92d72b 100644 --- a/src/serializers/index.ts +++ b/src/serializers/index.ts @@ -1,5 +1,9 @@ +import type pino from 'pino'; import { err, errWithCause } from 'pino-std-serializers'; +import { omitProperties } from './omitProperties'; +import { createOmitPropertiesSerializer } from './omitPropertiesSerializer'; + export const defaultOmitHeaderNames = [ 'x-envoy-attempt-count', 'x-envoy-decorator-operation', @@ -18,7 +22,7 @@ interface Socket { remoteAddress?: string; remotePort?: string; } -interface Request extends Record { +export interface Request extends Record { method: string; url: string; headers: Record; @@ -40,16 +44,23 @@ const isObject = (value: unknown): boolean => { return value != null && (type === 'object' || type === 'function'); }; -const req = (request: Request) => - isObject(request) - ? { - method: request.method, - url: request.url, - headers: request.headers, - remoteAddress: request?.socket?.remoteAddress, - remotePort: request?.socket?.remotePort, - } - : request; +export const createReqSerializer = (opts: SerializerOptions) => { + const req = (request: Request) => + isObject(request) + ? { + method: request.method, + url: request.url, + headers: omitProperties( + request.headers, + opts.omitHeaderNames ?? defaultOmitHeaderNames, + ), + remoteAddress: request?.socket?.remoteAddress, + remotePort: request?.socket?.remotePort, + } + : request; + + return req; +}; const res = (response: Response) => isObject(response) @@ -59,9 +70,25 @@ const res = (response: Response) => } : response; -export default { +export const createSerializers = ( + opts: SerializerOptions & Pick, +) => { + const omitHeaderNamesSerializer = createOmitPropertiesSerializer('headers', { + omitPropertyNames: opts.omitHeaderNames ?? defaultOmitHeaderNames, + }); + return { + ...defaultSerializers, + req: createReqSerializer(opts), + ...omitHeaderNamesSerializer, + ...opts.serializers, + }; +}; + +const defaultSerializers = { err, errWithCause, res, - req, + req: createReqSerializer({}), }; + +export default defaultSerializers;