Is it possible to define a unique request Id that is included in each log statement without handing the logger to each method/function call?
Technologies in use: NodeJS, Express, Winston
Is it possible to define a unique request Id that is included in each log statement without handing the logger to each method/function call?
Technologies in use: NodeJS, Express, Winston
Edited
Finally, I have created a library that makes all the work. https://github.com/davicente/express-logger-unique-req-id
It is a wrapper of Winston library, so you can use it the same way.
Let me know if it helps you
We had this same problem in several projects, and I couldn't finde any complete solution for this question. We are using same technologies (Node.js, Express.js and Winston for logs) I found a solution to this using a couple of libraries and wrapping Winston library: - node-uuid for creating unique identificators for each request - continuation-local-storage for sharing this IDs among different modules without sending req object in all the calls.
First I need to create and set the unique identificator with each request. I do it in the middleware:
var uuid = require('node-uuid');
var createNamespace = require('continuation-local-storage').createNamespace;
var myRequest = createNamespace('my request');
// Run the context for each request. Assign a unique identifier to each request
app.use(function(req, res, next) {
myRequest.run(function() {
myRequest.set('reqId', uuid.v1());
next();
});
});
After that I had to wrap Winston library, recovering the id from the context and adding to the message of the log:
var winston = require('winston');
var getNamespace = require('continuation-local-storage').getNamespace;
// Wrap Winston logger to print reqId in each log
var formatMessage = function(message) {
var myRequest = getNamespace('my request');
message = myRequest && myRequest.get('reqId') ? message + " reqId: " + myRequest.get('reqId') : message;
return message;
};
var logger = {
log: function(level, message) {
winstonLogger.log(level, formatMessage(message));
},
error: function(message) {
winstonLogger.error(formatMessage(message));
},
warn: function(message) {
winstonLogger.warn(formatMessage(message));
},
verbose: function(message) {
winstonLogger.verbose(formatMessage(message));
},
info: function(message) {
winstonLogger.info(formatMessage(message));
},
debug: function(message) {
winstonLogger.debug(formatMessage(message));
},
silly: function(message) {
winstonLogger.silly(formatMessage(message));
}
};
module.exports = logger;
I think it was a little bit complex, so I decided to write it down in a post. You can get more information from there: Express.js: Logging info with global unique request ID – Node.js
I hope this helps with your problem.
This answer has a problem: the counter goes back to 0 every time the node process is restarted. Turns out there is fairly simple to work around. You simply add an express middleware that tags each request called with a UUID using the uuid package.
const uuid = require('uuid');
const app = express();
app.use(function (req, next) {
req.id = uuid.v4();
next();
});
const uuidv4 = require('uuid/v4');
const app = express();
app.use(function (req, next) {
req.id = uuidv4();
next();
});
At the very beginning of your request handling add something like the following (or put it in its own file):
var makeID = (function() {
var index = 0;
return function() {
return index++;
}
})();
app.use(function(req, res, next) {
req.id = makeID()
next()
})
This will give every request a unique (sequential) id. Do not allow people to identify themselves with it, only use it internally!
When logging in Winston, you can enter metadata, to be displayed after the message (in the form ${name}=${value}
), which looks like this
app.use(function(req, res) {
winston.log('info', 'Test Log Message', { id: req.id });
res.end("Done.")
});
Hope this is helpful.