我正在使用Express作为框架在node.js中开发RESTful服务器,而目前使用Winston作为logger模块。 该服务器将处理大量的同时请求,并且能够使用类似“请求ID”的内容跟踪每个特定请求的日志条目对我非常有用。直接的解决方案是在每次我想要创建日志条目时将此ID添加为另一条日志记录信息,但这意味着将“请求ID”传递给服务器使用的每个方法。
我想知道是否有任何node.js / javascript模块或技术可以让我以更简单的方式执行此操作,而无需为每个特定请求携带请求ID。
答案 0 :(得分:16)
如果您自动增加,则以后的日志分析将无法唯一标识请求,因为不同的实例将生成冲突的ID,重新启动应用程序将自动导致ID冲突。
这是另一种可能的解决方案。
安装cuid:
npm install --save cuid
然后在您的主应用文件中:
var cuid = require('cuid');
var requestId = function requestId(req, res, next) {
req.requestId = cuid();
next();
};
// Then, at the top of your middleware:
app.use(requestId);
现在,您将获得一个不太可能发生冲突的友好请求ID,并且您将能够唯一地标识您的日志分析和调试请求,即使是跨多个实例,也可以重新启动服务器。
答案 1 :(得分:4)
您可以使用快递中每个请求附带的req
对象
因此,您在申请中要做的第一条路线是:
var logIdIterator = 0;
app.all('*', function(req, res, next) {
req.log = {
id: ++logIdIterator
}
return next();
});
然后在快递中的任何地方,您都可以访问id
对象中的req
:req.log.id
;
您仍然需要将一些数据传递给想要创建一些日志的函数。实际上,您可能在req.log
对象中具有日志记录功能,因此可以保证只有在有req.log
对象访问权限时才会进行日志记录。
答案 2 :(得分:2)
我正在努力寻找这个问题的解决方案。 关于这里建议的解决方案我不喜欢它的意思是它们意味着在项目的所有功能之间共享req对象。 我发现了一种混合你的方法(每个请求创建一个uuid)和一个允许在模块之间共享命名空间的库(continuation-local-storage)的解决方案。
您可以在其他答案中找到解释:https://stackoverflow.com/a/47261545/5710581
如果您想了解更多信息,我会在帖子中写下所有这些想法和所有代码,以便在一个地方解释所有内容: Express.js: Logging info with global unique request ID – Node.js
答案 3 :(得分:0)
您不应该使用全局变量。
我喜欢做的是在每次请求之前填充META对象。
我使用UUID生成器(https://github.com/kelektiv/node-uuid)来标识请求
这是一个例子
app.all('*', function(req, res, next) {
req.meta = {
ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
timestamp: uuid(),
user_agent: req.headers['user-agent'],
body: req.body,
}
return next();
})
答案 4 :(得分:0)
如@moka所述,在每个请求中使用请求ID是解决问题的关键。提取所有这些内容的另一种方法是使用 http-context 和 uuid
因此,请在所有所有中间件(设置为应用程序中间件而不是路由器中间件)之前的httpContext中设置UUID。现在您可以在代码中的任何位置获取uuid并将其记录下来。
这是我使用的示例实现
您可以在此处uuid in request
获得完整的参考const uuid = require('node-uuid');
const httpContext = require('express-http-context');
....
this.expressApp.use(httpContext.middleware);
this.expressApp.use((req, res, next) => {
httpContext.set('reqId', uuid.v4());
next();
});
现在,我已在自定义Pino记录器中使用此处设置的reqId'
public infoLogService (fileName): pino.Logger {
return pino({
level: 'info',
name: this.appService.getApp_name(),
messageKey: 'XXX-Logs',
base: {pid: process.pid, hostname: os.hostname,
timestamp: this.getTimeStamp(),
appName: this.appService.getApp_name(),
fileName: fileName,
request_id: **isNullOrUndefined(httpContext.get('reqId'))** ? 'Not an actual request ' : httpContext.get('reqId')
},
enabled: true,
useLevelLabels: true,
});
}
如果reqId为null,则表示记录器已插入启动Express App之前使用的代码中。希望您可以将其用作替代解决方案