简体   繁体   English

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

[英]how can I log every method call in node.js without adding debug lines everywhere?

I would like to log the user_id of the person making a request and the method name of every method called for a javascript class. 我想记录发出请求的人的user_id以及为javascript类调用的每个方法的方法名称。 For example: 例如:

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

Since everything is async user 35 and 78 might be doing stuff at the same time. 由于一切都是异步的,用户35和78可能同时在做东西。 So I want to make sure each log line starts with their user_id so I can grep for it and only see one user's activity at a time. 所以我想确保每个日志行都以他们的user_id开头,所以我可以grep它,并且一次只能看到一个用户的活动。

Is there a super clever way to do this without adding logger statements to every method? 有没有一种超级聪明的方法可以在不向每个方法添加记录器语句的情况下执行此操作?

The answer is essentially correct, but here's how to avoid infinite recursion 答案基本上是正确的,但这里是如何避免无限递归

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

Coffeescript CoffeeScript的

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

This is one alternative, not entirely sure how reliable it is though, it feels a bit wrong: 这是一种替代方案,但不完全确定它有多可靠,但感觉有点不对劲:

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

As you can see, it overwrites the call function - this creates a slight problem when you try to call console.log() so you need to swap the function back. 正如您所看到的,它会覆盖call函数 - 当您尝试调用console.log()时会产生一个小问题,因此您需要将函数交换回来。 But it seems to work! 但它似乎工作!

EDIT 编辑

Since this is tagged CoffeeScript: 由于这是标记的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

I'm guessing this is a web app, in which case if you are using connect you can use a logger middleware that logs the user and the URL path, which is probably sufficient. 我猜这是一个Web应用程序,在这种情况下,如果您使用连接,您可以使用记录用户和URL路径的记录器中间件,这可能就足够了。 Otherwise, you are going to have to do some metaprogramming along the lines of wrapping each function in a wrapper function to do the logging. 否则,您将不得不在包装函数中包装每个函数的行进行一些元编程来进行日志记录。

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

For this to work, your class method's must be named functions, not anonymous. 为此,您的类方法必须是命名函数,而不是匿名函数。

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM