【问题标题】:NodeJS Express - Global Unique Request IdNodeJS Express - 全局唯一请求 ID
【发布时间】:2016-08-20 22:01:23
【问题描述】:

是否可以在不将记录器交给每个方法/函数调用的情况下定义包含在每个日志语句中的唯一请求 ID?

使用的技术:NodeJS、Express、Winston

【问题讨论】:

  • 如果你愿意使用 ES6,你可能想使用Symbol
  • 很想,但我现在卡在 0.10.13 上
  • @MayorMonty 这有什么帮助?

标签: node.js express logging winston


【解决方案1】:

在您的请求处理的最开始添加类似以下内容(或将其放在自己的文件中):

var makeID = (function() {
  var index = 0;
  return function() {
   return index++;
  }
})();

app.use(function(req, res, next) {
  req.id = makeID()
  next()
})

这将为每个请求提供一个唯一的(顺序)ID。 不要让人们用它来认同自己,只能在内部使用!

登录 Winston 时,您可以输入元数据,在消息后显示(格式为 ${name}=${value}),如下所示

app.use(function(req, res) {
  winston.log('info', 'Test Log Message', { id: req.id });
  res.end("Done.")
});

希望这有帮助。

【讨论】:

  • 这是当前实现的解决方案,但是请求Id在其他模块/功能/方法中不可变,无需修改每个相关定义以包含请求Id或记录器。
  • 你不能只使用cookies吗?
  • 不需要 req 来访问 z cookie 吗?
  • 是的,或者您可以将所有打开的连接的reqres 保存在某种全局对象中
  • @smokedice 您是否最终找到了一种方法来通过您的服务记录请求 ID,而无需将 requestId 或记录器传递给其他模块?我现在正在寻找一种方法来做到这一点,似乎找不到一个好的解决方案。
【解决方案2】:

This answer有一个问题:每次重启node进程,计数器都会回到0。事实证明,解决方法相当简单。您只需添加一个快速中间件,该中间件使用 uuid 包标记每个调用的请求,并使用 uuid 包。

对于 uuid Pre-2.0

const uuid = require('uuid');
const app = express();
app.use(function (req, next) {
  req.id = uuid.v4();
  next();
});

对于 uuid 3.0+

const uuidv4 = require('uuid/v4');
const app = express();
app.use(function (req, next) {
  req.id = uuidv4();
  next();
});

【讨论】:

  • 这种方法会将问题从将记录器交给每个对象转移到将请求交给每个对象。
  • 生成的req.id真的是唯一的吗?或者,如果进程重新启动,您可以获得 2 个具有相同 ID 的会话?正如我在 uuid 文档中看到的,它不使用持久存储。
  • 深度要求 require('uuid/v4') 根据 uuid readme 已弃用。
【解决方案3】:

已编辑

最后,我创建了一个可以完成所有工作的库。 https://github.com/davicente/express-logger-unique-req-id

它是 Winston 库的包装器,因此您可以以相同的方式使用它。

如果对你有帮助,请告诉我


我们在几个项目中都遇到了同样的问题,我找不到任何完整的解决方案。我们使用相同的技术(Node.js、Express.js 和 Winston 用于日志) 我使用几个库和包装 Winston 库找到了一个解决方案: - node-uuid 用于为每个请求创建唯一标识符 - continuation-local-storage 用于在不同模块之间共享此 ID,而无需在所有调用中发送 req 对象。

首先,我需要为每个请求创建和设置唯一标识符。我在中间件中做:

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();
    });
});

之后我不得不包装 Winston 库,从上下文中恢复 id 并添加到日志的消息中:

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;

我觉得这有点复杂,所以我决定把它写在一个帖子里。您可以从那里获得更多信息:Express.js: Logging info with global unique request ID – Node.js

我希望这对您的问题有所帮助。

【讨论】:

  • 这适用于每个请求,我已经阅读了博客,它适用于它正在发送的每个请求,但是如果我有一个名为 test 的函数,我如何设置跟踪 ID 并在其中使用它logger.js,所以每当应用程序启动时,测试功能就会执行,我可以获得一个跟踪 id
  • 对不起,你说的我不太明白,你能再具体一点吗?
  • 我使用 winston 、 morgan 和 daily rotate 文件创建了一个记录器。问题是,如果我保存代码,只会生成日志文件夹和文件。如果我尝试点击路由,则文件夹不会创建基本上 http req 会照顾摩根,但即使我将它组合起来它也无法正常工作
  • node-uuid 已弃用。
猜你喜欢
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多