Skip to content

Feature: Child logger hook #4751

@brettwillis

Description

@brettwillis

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

🚀 Feature Proposal

As far as I can tell from Pino, we get a bit of a performance gain for child logger bindings that are provided when the child logger is instantiated (the bindings are pre-serialised).

Currently, Fastify just binds the request ID when creating a child logger:

fastify/lib/route.js

Lines 399 to 414 in c4cb3a8

function routeHandler (req, res, params, context, query) {
const id = genReqId(req)
const loggerBinding = {
[requestIdLogLabel]: id
}
const loggerOpts = {
level: context.logLevel
}
if (context.logSerializers) {
loggerOpts.serializers = context.logSerializers
}
const childLogger = logger.child(loggerBinding, loggerOpts)
childLogger[kDisableRequestLogging] = disableRequestLogging

I propose to have a hook function (as part of the Fastify config) that will enable us to add bindings to the child logger, with access to the request object.

Motivation

There are any number of scenarios where some logger bindings can be calculated on a per-request basis, other than just the request ID.

One such example is in Google Cloud Logging, where the trace context consists of multiple fields (not just one field), such as the trace and spanId, which should be parsed/calculated once and only once when the child logger is created, and immediately when created (not in a subsequent hook) so that all log entries (even early error logs if we don't even to process any hooks) get the bindings.

In such cases it would be great to have the pre-serialised performance win of child bindings, and also convenient access to the request object when binding.

Example

Perhaps something like below would allow us to arbitrarily modify or add to the child bindings for a request's child logger before that logger is created.

function routeHandler (req, res, params, context, query) { 
   const id = genReqId(req) 
  
-  const loggerBinding = { 
+  let loggerBinding = { 
     [requestIdLogLabel]: id 
   } 

+  if (bindRequestLoggerFn) {
+    loggerBinding = bindRequestLoggerFn(loggerBinding, req) || {};
+  }

   const loggerOpts = { 
     level: context.logLevel 
   } 
  
   if (context.logSerializers) { 
     loggerOpts.serializers = context.logSerializers 
   } 
   const childLogger = logger.child(loggerBinding, loggerOpts) 
   childLogger[kDisableRequestLogging] = disableRequestLogging

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions