How to integrate pino-http with AsyncLocalStorage?

695 Views Asked by At

I am using pino-http to log requests with the code below

import { pino } from 'pino';
import { pinoHttp } from 'pino-http';
import { v4 } from 'uuid';

export const logger = pino({
  enabled: process.env.LOG_ENABLED === 'true',
  formatters: {
    level: (label) => {
      return { level: label };
    },
  },
  level: process.env.LOG_LEVEL || 'info',
  name: process.env.LOGGER_NAME,
  redact: {
    paths: ['email', 'password', 'token'],
  },
  timestamp: pino.stdTimeFunctions.isoTime,
});

export const requestLogger = pinoHttp({
  logger,
  genReqId: function (req) {
    req.id = v4();
    return req.id;
  },
  customLogLevel: function (req, res, err) {
    if (res.statusCode >= 400 && res.statusCode < 500) {
      return 'warn';
    } else if (res.statusCode >= 500 || err) {
      return 'error';
    } else if (res.statusCode >= 300 && res.statusCode < 400) {
      return 'silent';
    }
    return 'info';
  },

  customProps: (req, res) => {
    const accountId = req.user ? req.user.id : null;
    const adminId = (req.session || {}).adminUser
      ? req.session.adminUser.id
      : null;
    return {
      accountId,
      adminId,
    };
  },
});

I would like to be able to also track the request id through the other functions, so I created a proxied logger

const proxiedLogger = new Proxy(logger, {
  get(target, property, receiver) {
    target = context.getStore()?.get('logger') || target;
    return Reflect.get(target, property, receiver);
  },
});


const contextMiddleware = (req: Request, res: Response, next: NextFunction) => {
  const child = logger.child({ requestId: v4() });
  const store = new Map();
  store.set('logger', child);
  return context.run(store, next);
};

How do I make pino-http use this logger for all requests? The issue is that pino-http comes with its own genReqId method

1

There are 1 best solutions below

0
On

A bit late but here's how I tackled that issue.

You can use pino-http's customProps for that, basically you want to pull the logger from the store, extract the requestId then return it.

 customProps: (req, res) => {
   const store = context.getStore()?.get("logger");

   if (!store) return {};
   const { requestId } = store.bindings();

   return { requestId }; // attach requestId to request logs
},