10

My request object contains a unique id which every log in my app must have.This id must also be propagated to any APIs I'm calling from my back-end Right now, I'm passing the request object everywhere. This is obviously not an ideal solution.Are there any suggestions?

CODE FLOW

Client------->Server(generate request id, use this for all logs)----->pass request id to any api call

Code:

app.use(function(req,res,next) {    
  logger.info("My message",req);
});
dm03514
  • 54,664
  • 18
  • 108
  • 145
Anurag Ojha
  • 101
  • 1
  • 1
  • 3
  • Code is just an example as to how I am passing the request context to my logger – Anurag Ojha Sep 18 '15 at 15:36
  • 2
    If all you need is the request id for logging, how about just passing the request id instead of the whole request object? I imagine it would be a lot more lightweight (i.e. just a number or string) – arcyqwerty Sep 18 '15 at 15:42
  • Hi, doesn't javascript pass the reference to an object, rather than the object itself?Will it really substantially affect the performance ? Anyway, my main concern here was to avoid passing an extra parameter in a lot of apis and logging calls.Thanks for your time though, appreciate it. – Anurag Ojha Sep 18 '15 at 18:46

3 Answers3

3

You can use the continuation-local-storage module. There is also the request-local module that is just a small layer on top of continuation-local-storage. Don't expect continuation-local-storage to always be perfect though...you will run into edge cases where the cls context will be invalid.

  • Thanks, I did try continuation-local-storage but it was losing context in most of the express-routes and api service calling modules. I'll give request-local a try though. Is there any other line of thinking which can accomplish this task? Appreciate the help, thanks. – Anurag Ojha Sep 18 '15 at 18:38
  • You're not going to have any better luck with `request-local` since it is just a small layer on top of `continuation-local-storage`. If you are extra careful about making sure your callback functions are bound to the correct CLS namespace then things will work, but that can be challenging with various Promise libraries and various connection pooling solutions, etc. I'm pretty sure you won't find anything safer than passing the req/res around for Node.js apps due to the nature of how Node.js supports async. – Patrick Steele-Idem Sep 18 '15 at 23:07
  • Oh well, passing parameters it is. Thanks for your help! – Anurag Ojha Sep 19 '15 at 08:51
  • Patrick, are you able to comment on why you will run into edge cases where cls context is invalid? I have found continuation-local-storage to be a bit flaky as in I can't always retrieve data that I set to that context. – Tim Hysniu Oct 23 '17 at 22:08
3

Here is a revised solution using the continuation-local-storage module.

Here is my context module. So far it only stores path, request time and correlation ID that it generates if it doesn’t receive one in the request.

'use strict';

const continuation = require('continuation-local-storage');
const cuid = require('cuid');

const appName = require('config').get('app_name');

class Context {

    static setup(req, res, next) {
        const session = continuation.createNamespace(appName);
        session.run(() => {
            session.set('context', new Context(req));
            next();
        });
    }

    constructor(req) {
        this.path = req.path;
        this.corrId = req.headers['x-correlation-id'] || cuid();
        this.requestTime = Date.now();
    }

    static current() {
        return continuation.getNamespace(appName).get('context');
    }
}

module.exports = Context;

My app.js includes:

const Context = require('./context');

app.use(Context.setup);

After that, any code can call Context.current() to get the current context of the Express request. I will use that for consistent logging.

pharsicle
  • 1,209
  • 1
  • 14
  • 18
  • Feels like the wrong answer, but I can't really put my finger on why. Ill have to ruminate some more. – Paul Dec 11 '16 at 03:16
  • Using `process.domain` is the wrong answer. I have a working solution with the `continuation-local-storage` module and will edit the original answer to reflect that. – pharsicle Dec 11 '16 at 03:30
0

Given this is the first link that shows up when I search for "express request context", I thought I'd give a more recent answer. I believe the correct place to store contextual information about a request/response lifecycle is in res.locals as per the Express docs. According to another SO answer, req.locals is also used however there is no mention of this in the docs and the type definitions do not allow for it out of the box.

Gustavo Hoirisch
  • 1,637
  • 12
  • 19