5

在我的 node.js 应用程序中,每当我收到请求时,我想用一些唯一 ID “标记”它,并能够通过此 ID 跟踪与此请求相关的所有活动(日志语句)。因此,当请求进入并将其传递给较低的应用程序层(服务、数据库调用等)时,我希望能够收集与给定请求 ID 匹配的所有日志,以重建其通过应用程序的旅程。

所以有了这张图片,我现在使用request-local模块,但它做了一些让我失败的重魔法(来自多个请求的日志获得相同的 ID)。

代码主要基于 Promises(不是普通的旧节点回调),我使用高阶函数来为我的实际函数提供依赖关系(在启动期间构建应用程序树)。

第一个也是非常明显的解决方案是将此请求 ID 传递给每个调用的函数,但这是一场灾难,我不会这样做。

您如何(可靠地)进行这种请求跟踪,而不显式将此 id/context 作为额外参数传递给所有级别的函数?

4

2 回答 2

3

已编辑

这个图书馆可以完成这项工作。它是 Winston 库的一个包装,所以它的配置方式相同,它为每个请求生成一个唯一 ID,并在每个日志中打印它

https://github.com/davicente/express-logger-unique-req-id

================

我提出了一种方法,其中 id 将根据请求是唯一的,您不需要在不同的调用和模块之间传递任何对象(req,id ...)。这意味着使用一个库来创建唯一的 id,我选择了 node-uuid,另一个库在不同的模块(continuation-local-storage)之间共享上下文变量,但根据请求使用命名空间,以便为所有调用(甚至是异步调用)。此外,我包装了 Winston 库,以便在每个日志中打印请求 ID。有了这个,您将能够跟踪一个请求的所有日志。

我在这里用代码示例写了一个完整的解释https://solidgeargroup.com/express-logging-global-unique-request-identificator-nodejs

于 2017-12-19T16:57:50.260 回答
1

我相信您正在寻找的是一个逻辑流 ID,它应该是唯一的,并且在您的后端启动的每个新请求时都会生成。如果这个假设是正确的,我通常会在我的 express 路由器上创建一个中间件来生成一个新的随机流 id(带有randomstring)。为了确保这个流 id 是唯一的,我添加了时间戳。为了将此流 id 传递给下一个中间件,我们应该将其存储在 res.locals 下(此处为文档)您的中间件可能如下所示:

//middleware flow.js
var random = require('randomstring');

var generate = function(){
    var dt = new Date();
    return random.generate() + dt.toISOString();
}
module.exports.createID = function(req, res, next){
    //store flowid in res - this hold state over the request life time
    res.locals.flowid = generate();
    next();
}

现在我们可以使用以下方法在应用程序中注入这个中间件:

var flowcontrol = require('flow.js');
var middleware = require('middleware.js');

app.use(flowcontrol.createID);

//route example
app.get('/api/awesomeresource', middlewares.first, middlewares.second);

使用这种方法,您将能够在每个中间件上记录相同的流 id,例如:

//middleware.js
module.exports.first = function(req, res, next){
   console.log(res.locals.flowid + " - First i did this...");
   //your logic here
   next();
}
module.exports.second = function(req, res, next){
   console.log(res.locals.flowid + " - Second i did this...");
   //your logic here before the response
   res.sendStatus(200);
}

结果 GET /api/awesomeresource HTTP/1.1 将是以下控制台日志:

> R90A56nEmZWYK73NOEVbWv2RS6DolO4D2017-12-07T10:29:39.291Z - First i did
> this... 
> R90A56nEmZWYK73NOEVbWv2RS6DolO4D2017-12-07T10:29:39.291Z -
> Second i did this...

这意味着您可以通过此标记跟踪某种日志文件,并在需要时调试您的后端逻辑。

干杯

于 2017-12-07T11:04:04.130 回答