如何在 node.js 中记录每个方法调用而不在任何地方添加调试行?

Posted

技术标签:

【中文标题】如何在 node.js 中记录每个方法调用而不在任何地方添加调试行?【英文标题】:how can I log every method call in node.js without adding debug lines everywhere? 【发布时间】:2013-03-31 03:56:54 【问题描述】:

我想记录发出请求的人的 user_id 以及为 javascript 类调用的每个方法的方法名称。例如:

35 - log_in
35 - list_of_other_users
78 - log_in
35 - send_message_to_user
35 - connect_to_redis
78 - list_of_other_users

由于一切都是异步的,用户 35 和 78 可能同时在做一些事情。所以我想确保每个日志行都以他们的 user_id 开头,这样我就可以 grep 并且一次只能看到一个用户的活动。

有没有一种超级聪明的方法来做到这一点,而无需在每个方法中添加记录器语句?

【问题讨论】:

How do I debug Node.js applications?的可能重复 【参考方案1】:

答案基本正确,但这里是如何避免无限递归

Javascript

(function () 
  var oldCall = Function.prototype.call;
  var newCall = function(self) 
    Function.prototype.call = oldCall;
    console.log('Function called:', this.name);
    var args = Array.prototype.slice.call(arguments, 1);
    var res = this.apply(self, args);
    Function.prototype.call = newCall;
    return res
  
  Function.prototype.call = newCall;
)();

咖啡脚本

do ->
  oldCall = Function::call
  newCall = (self) ->
    Function::call = oldCall
    console.log "Function called: #this.name"
    args = Array.prototype.slice.call arguments, 1
    res = this.apply self, args
    Function::call = newCall
    res
  Function::call = newCall

【讨论】:

这很好,但您能否阐明其工作原理并提供一个使用示例?它非常先进,SE 也适用于初学者/中级用户。 :D 没有得到实际的函数名,而是Function called: Function called: addListener Function called: removeListener Function called: addListener Function called: removeListener Function called: addListener【参考方案2】:

这是另一种选择,虽然不完全确定它有多可靠,但感觉有点不对:

(function () 
  var oldCall = Function.prototype.call;
  var newCall = function(self) 
    Function.prototype.call = oldCall;
    console.log('Function called:', this.name);
    var args = Array.prototype.slice.call(arguments, 1);
    Function.prototype.call = newCall;
    this.apply(self, args);
  
  Function.prototype.call = newCall;
)();

如您所见,它覆盖了 call 函数 - 当您尝试调用 console.log() 时,这会产生一个小问题,因此您需要将函数交换回来。但它似乎有效!

编辑

由于这被标记为 CoffeeScript:

do ->
  oldCall = Function::call
  newCall = (self) ->
    Function::call = oldCall
    console.log "Function called: #this.name"
    args = Array.prototype.slice.call arguments, 1
    Function::call = newCall
    this.apply self, args
  Function::call = newCall

【讨论】:

这对我来说是一个无限递归,因为 slice 是作为函数调用的。我必须在设置 newCall 之前移动切片调用并将结果作为下面的变量传递。不确定现在是否有效【参考方案3】:

我猜这是一个网络应用程序,在这种情况下,如果您使用连接,则可以使用记录用户和 URL 路径的记录器中间件,这可能就足够了。否则,您将不得不按照将每个函数包装在包装函数中的方式进行一些元编程以进行日志记录。

function logCall(realFunc, instance) 
    return function() 
      log.debug('User: ' + instance.user_id + ' method ' + realFunc.name);
      return realFunc.apply(instance, arguments);
    ;

为此,您的类方法必须是命名函数,而不是匿名的。

function sendMessage() 
    //code to send message
    //can use `this` to access instance properties

function MyClass(userId) 
    this.userId = userId; //or whatever
    this.sendMessage = logCall(sendMessage, this);
    //repeat above line for each instance method you want instrumented for logging

【讨论】:

以上是关于如何在 node.js 中记录每个方法调用而不在任何地方添加调试行?的主要内容,如果未能解决你的问题,请参考以下文章

Node.JS MySQL 将结果记录到控制台而不被要求和奇怪的行为

如何在 node.js 中获取目录大小而不递归遍历目录?

如何在浏览器中访问远程 node.js 应用程序,而不是在本地主机上

Node.js 调试

node.js:如何在 forEach 循环中使用异步调用实现路由方法?

在 Mongoose (mongodb node.js) 中,如何更新现有值并插入缺失值,而不删除未指定的值?