hapi-pino icon indicating copy to clipboard operation
hapi-pino copied to clipboard

Logging information from user credentials

Open chrisshiplet opened this issue 4 years ago • 6 comments

It's useful for me to be able to access a user's ID or email address when investigating errors reported from our Hapi project. This metadata is in Hapi's request.auth.credentials object, so using hapi-pino I can access that information for request logs with a custom serializer since they include the req object. However, for error logs, the req object does not seem to be included at all.

The easiest fix would be to simply include the req object with errors... but I also wonder if anyone has ideas about logging the credentials object across the board? A lot of logging/issue tracking services like Sentry have first class support for tracking users like this and it'd be nice for this to "just work" without messing around with the req serializer.

chrisshiplet avatar Jan 08 '21 21:01 chrisshiplet

The easiest fix would be to simply include the req object with errors...

Great idea! Would you like to send a Pull Request to address this issue? Remember to add unit tests.

but I also wonder if anyone has ideas about logging the credentials object across the board?

This has some GDPR implications and I prefer not to release something that could cause issues for users.

mcollina avatar Jan 09 '21 12:01 mcollina

@chrisshiplet Can you explain how you included the credentials using a custom serializer? For me the req in the serializer seems to no actually be the hapi request object and therefore request.auth.credentials is not available.

I also tried using the getChildBindings option to add credentials to all request logs but it gets called to early in the request cycle when hapi has not yet populated request.auth. Once the child logger has been created it is used for the entire request and never updated.

markopy avatar Nov 02 '21 22:11 markopy

Regarding the original issue here, apologies I never got time to work on it! Unfortunately I no longer work on the project this feature was required for. I also didn't consider the GDPR implications of this at the time since we're not subject to it, although I'm currently learning all about CCPA...

@markopy Sure thing! I'm not sure how useful this will be for you. I'm definitely getting the request object I expect right in the serializer. I pass this into pino's options object:

  serializers: {
    req: req => ({
      method: req.method.toUpperCase(),
      url: req.url,
      user: req.auth &&
        req.auth.credentials && {
          userId: req.auth.credentials.sub,
          email: req.auth.credentials.email,
        },
    }),
  },

and it "just works".

This project was on Hapi ^19.2.0, Pino ^6.6.0, and Hapi-Pino ^8.3.0.

chrisshiplet avatar Nov 03 '21 16:11 chrisshiplet

Thanks @chrisshiplet. For some reason on Hapi 20.2.1, Pino 6.13.3 and Hapi-Pino 8.5.0 this doesn't work for me because req doesn't have auth or any of the other expected properties of the Hapi request object.

What did work though is this:

formatters: {
    log: (obj) => ({
        credentials: obj.req.auth.credentials,
        ...obj
    })
},

which I found via issue https://github.com/pinojs/hapi-pino/issues/121#issuecomment-756901305 I'm new to Hapi and Pino so can't really explain what's going on but this seems to work for my needs so far.

markopy avatar Nov 03 '21 22:11 markopy

I solved this problem by using options.customRequestCompleteMessage here you have the fully filled request object available. But I would be happy if I could configure more then only the message object but also the other properties and return not only a string but an object.

svrnwnsch avatar Feb 24 '23 16:02 svrnwnsch

In case anyone else needs this, my previous method using formatters no longer works after https://github.com/hapijs/hapi-pino/pull/157 removed req from being added again during response logging. I now use the following to rebind the child logger with additional auth information once it is available:

const nullLogger = require('abstract-logging')

// Create new hapi-pino child logger which adds additional information when the request
// has reached a stage where request.auth is available.
server.ext('onPreHandler', (request, h) => {
    if (request.logger && request.logger !== nullLogger) {
        request.logger = request.logger.child({
            credentials: request?.auth?.credentials
        })
    }
    return h.continue;
});

This is better and cleaner since the auth information will now be attached to all log calls happening during request handling as well as to the final response logging.

markopy avatar Nov 11 '23 15:11 markopy