DEV Community

Discussion on: Tracing requests in Node.js?

 
henryjw profile image
Henry Williams

I definitely like this solution of passing the context instead of the the logger. Thanks a lot for the suggestions!

By the way, is this also a solution you've had to go with for log tracing in Node? Or have you never had this issue? Just curious to know if I'm approaching this problem incorrectly.

Thread Thread
 
qm3ster profile image
Mihail Malo

It's just the most obvious pattern for me. I haven't made large HTTP APIs in nodejs, but I have done something similar.

It just seems logical:
Q1: I need to access the context, the shape of which is technology-specific and won't change any time soon in a function I call from the handler that has access to the context.
A1: Well, just pass it in, yo!

Q2: I want to have type-annotated functions that make use of the context in my files, without bringing any annotation into my files.
A2: Import the CODE of the functions explicitly, to reference the annotated file, and pass them the "untyped" but well known context object.

Thread Thread
 
henryjw profile image
Henry Williams

Makes sense. Thanks again for sharing the knowledge!

Thread Thread
 
sathishkumarsoundharajan profile image
Sathish

Hi Michal that weakmap approach. Now instead of passing logger needed to pass the request to every function. How is that different from Henry class solution.. am I misunderstood something. ? Thanks for your help

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

@sathishkumarsoundharajan When it comes in as a constructor parameter or method parameter, to have it be typed in your editor/IDE, you have to annotate it in place.
@henryjw posed a particular problem, where they didn't want type annotations inside the handler method files. In order to still have types available, the logger must be imported instead of injected. So, we import a function that provides the logger.
How does it tie the logger to the current context? Well, why not use the request.
So, we import the logger "factory", give it the untyped "req" object, and get back a strongly typed (in terms of editor autocompletion) logger object.
Can do it like this if we don't want to have a special middleware createing the logger first:

// logger.js
const map = new WeakMap

export const get = req => {
  const logger = map.get(req)
  if (logger) return logger
  const newLogger = new Logger(req.something, req.somethingElse)
  map.set(req, newLogger)
  return newLogger
}

So, if your whole project is in TypeScript or something, it isn't a big advantage.
And if you don't care about typings, it isn't a big advantage.
But it solves the unique specific problem posed in the post.

It's still less coupling/boilerplate than providing specifically the logger as a service constructor argument or method argument. All mentions of "logger" will disappear from the routing glue code (except where you want to log for routing reasons).