【问题标题】:How to identify request (by ID) through middleware chain in Express.如何通过 Express 中的中间件链识别请求(通过 ID)。
【发布时间】:2013-07-16 02:59:27
【问题描述】:

我正在 node.js 中开发一个 RESTful 服务器,使用 Express 作为框架,目前使用 Winston 作为记录器模块。 该服务器将处理大量的同时请求,并且能够使用“请求 ID”之类的东西来跟踪每个特定请求的日志条目对我来说非常有用。直接的解决方案是每次我想创建日志条目时将此 ID 作为另一条日志信息添加,但这意味着将“请求 ID”传递给服务器使用的每个方法。

我想知道是否有任何 node.js/javascript 模块或技术可以让我以更简单的方式执行此操作,而无需携带每个特定请求的请求 ID。

【问题讨论】:

    标签: node.js logging express


    【解决方案1】:

    您可以使用req 对象,该对象确实与 express 中的每个请求一起提供。
    因此,您在应用程序中执行的第一条路线是:

    var logIdIterator = 0;
    
    app.all('*', function(req, res, next) {
      req.log = {
        id: ++logIdIterator
      }
      return next();
    });
    

    然后在 express 中的任何位置,您都可以在 req 对象中访问该 idreq.log.id;
    您仍然需要将一些数据传递给确实想要创建一些日志的函数。事实上,您可能在req.log 对象中具有日志记录功能,这样可以保证只有在可以访问req.log 对象时才会发生日志记录。

    【讨论】:

    • 感谢您的回答。我也使用您提出的解决方案。但是,我想自动识别要应用的 ID。我实现的一个解决方案是将 ID 存储在请求对象中,当调用我的自定义日志函数时,它会在调用堆栈中查找 ID。我知道这是错误的有几个原因(在“严格模式”下禁止访问其他函数的参数信息,效率不高,并且在触发 I/O 事件时获取新堆栈)。我想这是不可能的,您提出的解决方案似乎是最适合的解决方案。
    【解决方案2】:

    如果你自动递增,你以后的日志分析将无法唯一识别请求,因为不同的实例会产生冲突的 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,并且您将能够唯一地标识您的日志分析和调试请求,甚至跨多个实例和服务器重启。

    【讨论】:

    • 是的,这当然是更好的解决方案,但问题在于你如何在winston日志中公开id,这样你就不会产生太多的数据重复。
    • 我也会使用域(或者他们决定用什么来替换域),这样您就不会通过在整个代码层中向下传递请求信息来污染函数调用。
    • 域已被弃用,并且没有具体的替换计划。
    • 查看Continuation Local Storage 在调用链中传递这些类型的值
    【解决方案3】:

    您不应该使用全局变量。

    我喜欢做的是在每次请求之前填充一个 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】:

      我一直在努力寻找解决此问题的方法。 我不喜欢这里建议的解决方案的一点是,它们暗示在项目中的所有函数之间共享 req 对象。 我发现了一个将您的方法(为每个请求创建一个 uuid)和一个允许在模块之间共享命名空间的库(continuation-local-storage)混合的解决方案。

      您可以在另一个答案中找到解释:https://stackoverflow.com/a/47261545/5710581

      如果您想了解更多信息,我将所有这些想法和所有代码写在一篇文章中,以便在一个地方解释所有内容: Express.js: Logging info with global unique request ID – Node.js

      【讨论】:

        【解决方案5】:

        正如@moka 所说,在每个请求中使用请求ID 是解决问题的关键。另一种抽象所有这些的方法是利用 http-contextuuid

        所以在所有中间件之前在 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 应用程序之前使用的代码中。希望您可以将其用作替代解决方案

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-24
          • 1970-01-01
          • 2014-09-01
          • 1970-01-01
          • 2015-09-16
          • 1970-01-01
          • 2012-03-31
          • 2019-09-16
          相关资源
          最近更新 更多