我目前正在使用Express 4和Node 8。我希望能够记录应用程序中发生的某些事情,并将会话ID作为将日志链链接在一起的方式。我正在使用winston进行日志记录。
问题:如何从应用中的任何位置访问此会话ID,以便将其包含在日志中?
我知道您不能将会话ID设置为全局变量,因为传入的后续请求将覆盖设置的任何内容。
此外,我知道可以将会话ID从路由层传递给需要它的所有其他函数,但是当最深层次的函数需要会话ID仅用于记录时,这可能相当麻烦。
对于多线程应用程序,每个线程都可以拥有自己的内存池,以便它可以安全地保存全局日志记录关联ID,而不会受到其他请求的干扰。但是,由于Node是单线程的,所以这似乎不可能,除非我遗漏了一些东西。
是否有办法拥有特定于请求的全局池,或者是否有更好的方法在每个日志语句中包含相关ID?
答案 0 :(得分:2)
我遇到了同样的问题,经过大量的研究,我终于找到了解决问题的方法。 我在这个问题中解释过:NodeJS Express - Global Unique Request Id 但基本上我使用了2个库: - node-uuid:为每个请求生成唯一ID - continuation-local-storage:与需要它的不同模块共享id。
我在这篇文章中用完整的代码示例写下了所有这些信息: https://solidgeargroup.com/express-logging-global-unique-request-identificator-nodejs
在我的情况下,当我使用Winston进行日志记录时,该示例是使用此库创建的,但它可以与任何其他库一起使用。
答案 1 :(得分:1)
问题:如何从应用中的任何位置访问此会话ID,以便将其包含在日志中?
来自传入请求的req
对象是特定于请求的对象,它将具有当前请求的状态(包括会话信息)。在node.js中真的没有其他办法可以做。正如您似乎已经知道的那样,由于node.js的共享单线程体系结构,没有像特定于请求的全局变量这样的东西,你可以放置一些你可以从任何地方访问的东西,它会告诉你你的会话重新服务。
如果要访问会话状态,则必须将req
对象或会话状态本身向下传递到要记录的级别。实际上没有其他办法可以做。
据我所知,您不能将会话ID设置为全局变量,因为传入的后续请求将覆盖设置的任何内容。
正确。试图将任何特定于请求的状态放在全局空间中只会导致它经常被交错工作的几个不同请求的协作事件处理打乱。
对于多线程应用程序,每个线程都可以拥有自己的内存池,以便它可以安全地保存全局日志记录关联ID,而不会受到其他请求的干扰。但是,由于Node是单线程的,所以这似乎不可能,除非我遗漏了一些东西。
你没有遗漏任何东西。
是否有办法拥有特定于请求的全局池,或者是否有更好的方法在每个日志语句中包含相关ID?
不,没有。您只需传递req
对象或将特定于会话的状态下调到您要记录的级别。没有特定于请求的全局池。 node.js不保持某种状态,关于哪个请求在任何给定时间运行代码。您可能已经知道,一个请求可以开始处理,然后在等待某些异步操作时将控制权返回给系统而另一个请求开始处理,然后当它等待某些异步操作时返回控制时,前者获取事件并启动执行代码。当后续异步事件导致新代码再次执行请求时,堆栈再次为空(其上没有特定于请求的状态)。
使这个可能或成立的可能关键在于如何构建代码,在相当低的级别提供哪些对象,以便您可以找出可以将会话信息附加到哪个对象,这使得它可以在您可以访问的位置需要它。这不是一般的解决方案,但取决于代码的确切布局和结构,因此如果没有看到您想到的具体代码,除了“将会话信息传递到您需要的位置”之外,我们无法提供更具体的建议。它”。