Henry Williams
Posted on January 21, 2019
TLDR;
- How can I maintain request context without having to pass the logger (or requestId) around and without using
cls-hooked
? - If there's no better way than passing the logger, how do I the carry the type info of the logger(ideally without JSDocs)?
Any one using a different pattern that's cleaner than passing the logger around? I've tried using express-http-context (and other cls-hooked
based libraries), but it isn't very reliable because the context gets lost in some cases.
The only slightly better approach I've come up with is to make all modules into classes so that only the constructor needs the logger, but then the logger still has to be passed down from the caller.
Another problem with passing the logger around is that the typing information is lost, so I have to remember the structure of the object. It's not a big deal for me, but it leads to subtle bugs, especially for developer that aren't as familiar with the codebase as I am.
Current solution
// routes.js
app.get(
'/api/v1/customer/:id',
async (req, res, next) => {
const id = req.params.id
// The logger contains multiple fields request-specific fields like
// request ID and authorization level
const logger = req.logger
const customer = await customerService.get(id, logger)
/// ... process and return response
}
)
// customer-service.js
module.exports.get = async (id, logger) {
/// ...
}
module.exports.create = async (customer, logger) {
// ...
}
Improved solution
// routes.js
app.get(
'/api/v1/customer/:id',
async (req, res, next) => {
const id = req.params.id
// The logger contains multiple fields request-specific fields like
// request ID and authorization level
const logger = req.logger
const customerService = new CustomerService(logger)
const customer = await customerService.get(id)
/// ... process and return response
}
)
app.post(
'/api/v1/customer',
async (req, res, next) => {
const customer = req.body
const logger = req.logger
// Downside: still have to pass logger to constructors
const customerService = new CustomerService(logger)
const customer = await customerService.create(customer)
// ... process and return response
}
)
// customer-service.js
class CustomerService {
constructor(logger) {
// logger is only passed into the constructor
this.logger = logger
}
module.exports.get = async (id) {
// ...
this.logger.info(/*data to log*/)
// ...
}
module.exports.create = async (customer, logger) {
// ...
this.logger.info(/*data to log*/)
// ...
}
}
Any solutions or tips are greatly appreciated :)
Posted on January 21, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.