【问题标题】:Adding timestamps to all console messages为所有控制台消息添加时间戳
【发布时间】:2013-09-19 18:55:35
【问题描述】:

我有一个完整的、已部署、基于 Express 的项目,其中包含许多 console.log() 和 console.error() 语句。 该项目使用永远运行,将 stdout 和 stderr 定向到 2 个单独的文件。

这一切都很好,但现在我缺少时间戳 - 确切地知道错误发生的时间。

我可以在我的代码中进行某种搜索/替换,或者在每个文件中使用一些覆盖控制台的 npm 模块,但我不想触及每个模型/路由文件,除非我绝对必须这样做。

有没有一种方法,比如 Express 中间件,可以让我为每次调用添加时间戳,还是必须手动添加?

【问题讨论】:

标签: node.js express console


【解决方案1】:

事实证明,您可以覆盖 app.js 文件顶部的控制台功能,并使其在所有其他模块中生效。我得到的结果好坏参半,因为我的一个模块被分叉为child_process。一旦我将该行也复制到该文件的顶部,一切正常。

为了记录,我安装了模块console-stampnpm install console-stamp --save),并将这一行添加到app.js和childProcess.js的顶部:

// add timestamps in front of log messages
require('console-stamp')(console, '[HH:MM:ss.l]');

我现在的问题是连接记录器的:date 格式使用UTC 格式,而不是我在其他控制台调用中使用的格式。这很容易通过注册我自己的时间格式来解决(并且作为副作用,需要console stamp 附带的dateformat 模块,而不是安装另一个):

// since logger only returns a UTC version of date, I'm defining my own date format - using an internal module from console-stamp
express.logger.format('mydate', function() {
    var df = require('console-stamp/node_modules/dateformat');
    return df(new Date(), 'HH:MM:ss.l');
});
app.use(express.logger('[:mydate] :method :url :status :res[content-length] - :remote-addr - :response-time ms'));

现在我的日志文件看起来井井有条(更好的是,可解析):

[15:09:47.746] staging server listening on port 3000
[15:09:49.322] connected to database server xxxxx successfully
[15:09:52.743] GET /product 200 - - 127.0.0.1 - 214 ms
[15:09:52.929] GET /stylesheets/bootstrap-cerulean.min.css 304 - - 127.0.0.1 - 8 ms
[15:09:52.935] GET /javascripts/vendor/require.js 304 - - 127.0.0.1 - 3 ms
[15:09:53.085] GET /javascripts/product.js 304 - - 127.0.0.1 - 2 ms
...

【讨论】:

  • 我找不到它的文档,但似乎 ":​​mm" 指的是月份,而 ":MM" 是您实际想要使用的格式
  • 你应该根据@user603124 所说的更改分钟部分。对于分钟,字符串为 :MM (github.com/starak/node-console-stamp)
  • 感谢您的评论。已更正!
  • 似乎您不再需要将 HH:MM:ss.l 括在括号中——它会自动进行
  • 仅供参考 logger 已替换为 morgan github.com/senchalabs/connect#middleware
【解决方案2】:

log-timestamp 模块适合我。

npm install log-timestamp

使用简单:

console.log('Before log-timestamp');
require('log-timestamp');
console.log('After log-timestamp');
Before log-timestamp
[2012-08-23T20:08:32.000Z] After log-timestamp

【讨论】:

    【解决方案3】:

    使用以下内容创建一个文件:

    var log = console.log;
    
    console.log = function(){
      log.apply(console, [Date.now()].concat(arguments));
    };
    

    在您记录任何内容之前,在您的应用中需要它。如果需要,对 console.error 执行相同操作。

    请注意,如果您使用该解决方案,该解决方案将破坏变量插入 (console.log("he%s", "y") // "hey")。如果需要,只需先记录时间戳:

    log.call(console, Date.now());
    log.apply(console, arguments);
    

    【讨论】:

    • 如果它是同一个应用程序/进程,则不是。控制台是一个全局对象,因此如果您像这样劫持它的一个功能,它将继续被共享该全局对象的所有文件劫持。
    • 所以这应该/可以放在 app.js 文件中?
    • 是的。
    • 我建议改用 console-stamp
    • 这不是一个好的解决方案 - 它要么破坏变量插入(因此不能用作替换),要么在不同的行上打印日期和日志输出。
    【解决方案4】:

    如果您想要一个没有其他外部依赖的解决方案,但又想保留 console.log 的全部功能(多参数、变量插入),您可以使用以下代码:

    var log = console.log;
    
    console.log = function () {
        var first_parameter = arguments[0];
        var other_parameters = Array.prototype.slice.call(arguments, 1);
    
        function formatConsoleDate (date) {
            var hour = date.getHours();
            var minutes = date.getMinutes();
            var seconds = date.getSeconds();
            var milliseconds = date.getMilliseconds();
    
            return '[' +
                   ((hour < 10) ? '0' + hour: hour) +
                   ':' +
                   ((minutes < 10) ? '0' + minutes: minutes) +
                   ':' +
                   ((seconds < 10) ? '0' + seconds: seconds) +
                   '.' +
                   ('00' + milliseconds).slice(-3) +
                   '] ';
        }
    
        log.apply(console, [formatConsoleDate(new Date()) + first_parameter].concat(other_parameters));
    };
    

    您可以修改 formatConsoleDate 函数以根据需要设置日期格式。

    此代码只需在您的主 JavaScript 文件顶部编写一次。

    console.log("he%s", "y") 将打印如下内容:

    [12:22:55.053] hey
    

    【讨论】:

    • 谢谢,这个“无依赖”的答案正是我所需要的。
    • 搞乱了文件:行信息:(
    【解决方案5】:

    您也可以使用log-timestamp 包。它非常简单,而且还可以自定义。

    【讨论】:

      【解决方案6】:

      这个实现很简单,支持console.log的原始功能(传递单个对象和变量替换),不使用外部模块并在一次调用console.log中打印所有内容:

      var origlog = console.log;
      
      console.log = function( obj, ...placeholders ){
          if ( typeof obj === 'string' )
              placeholders.unshift( Date.now() + " " + obj );
          else
          {
              // This handles console.log( object )
              placeholders.unshift( obj );
              placeholders.unshift( Date.now() + " %j" );
          }
      
          origlog.apply( this, placeholders );
      };
      

      【讨论】:

      • 谢谢,与此线程中的其他实现相比,这似乎非常简单,而且似乎工作得很好。
      【解决方案7】:

      如果您愿意,您可以通过在“控制台”类中扩展节点的构建来为您的应用程序创建自定义记录器。请参考以下实现

      "use strict";
      
      const moment = require('moment');
      const util = require('util');
      const Console = require('console').Console;
      
      class Logger extends Console {
          constructor(stdout, stderr, ...otherArgs) {
              super(stdout, stderr, ...otherArgs);
          }
      
          log(...args) {
              super.log(moment().format('D MMM HH:mm:ss'), '-', util.format(...args));
          }
      
          error(...args) {
              super.error(moment().format('D MMM HH:mm:ss'), '-', util.format(...args));
          }
      }
      
      module.exports = (function() {
          return new Logger(process.stdout, process.stderr); 
      }());

      之后,你可以在你的代码中使用它:

      const logger = require('./logger');
      
      logger.log('hello world', 123456);
      logger.error('some error occurred', err);

      【讨论】:

        【解决方案8】:

        这不是一个直接的答案,但您是否研究过winston.js?它有更多的日志记录选项,包括记录到 json 文件或数据库。默认情况下,这些总是有时间戳。只是一个想法。

        【讨论】:

        • 我已经研究了很多东西,现在,我想在现有的已部署项目中添加一些东西 - 无需接触太多代码
        【解决方案9】:
        app.use(morgan('[:date[web]] :method :url :status :res[content-length] - :remote-addr - :response-time ms'))
        

        【讨论】:

          【解决方案10】:

          您可以使用来自https://nodejs.org/api/util.html 的函数util.log

          请注意,它自 6.0.0 版以来已被弃用。

          对于更高版本,您应该"Use a third party module instead."

          【讨论】:

          • 已弃用:使用第三方模块。
          【解决方案11】:

          我正在尝试覆盖 console 对象 - 似乎运行良好。要使用,请将下面的代码保存在一个文件中,然后导入覆盖代理对象,然后正常使用。

          (请注意,这需要 babel 转译,并且不适用于不支持 JavaScript Proxy 构造函数的环境,例如 IE 11)。

          import console from './console-shadow.js'
          
          console.log(...)
          console.warn(...)
          console.error(...)
          
          // console-shadow.js
          
          // Only these functions are shadowed by default
          const overwrites = ['log', 'warn', 'info', 'error']
          
          export default new Proxy(
            // Proxy (overwrite console methods here)
            {},
          
            // Handler
            {
              get: (obj, prop) =>
                prop in obj
                  ? obj[prop]
                  : overwrites.includes(prop)
                  ? (...args) => console[prop].call(console, new Date(), ...args)
                  : console[prop],
            }
          )
          
          

          基本上我用 JavaScript 代理对象覆盖控制台对象。当您调用.log.warn 等时,被覆盖的控制台将检查您调用的是否是函数,如果是,它将在日志语句中注入日期作为第一个参数,然后是所有参数。

          我认为console 对象实际上做了很多事情,但我并不完全理解。所以我只拦截console.logconsole.infoconsole.warnconsole.error的电话。

          【讨论】:

            【解决方案12】:

            为了避免安装外部模块,一种更基本的方法可能是实现一个简单的功能,例如:

            function timeStamp(message){
                console.log ( '[' + new Date().toISOString().substring(11,23) + '] -', message )
            }
            

            然后我简单地这样称呼它:

            timeStamp('this is my logline!!');
            

            结果将是:

             LOG  [15:22:30.682] - this is my logline!!
            

            当然你可以将日期格式化成你需要的最佳格式,并将功能扩展为console.error、debug等

            【讨论】:

              【解决方案13】:

              像这样使用事件监听器,

              process.on('error', function() { 
                 console.log('Error Occurred.');
              
                 var d = Date(Date.now()).toString();
                 console.log.call(console, d); // Wed Aug 07 2019 23:40:07 GMT+0100 (GMT+01:00)
              });
              

              编码愉快 :)

              【讨论】:

                猜你喜欢
                • 2021-01-20
                • 1970-01-01
                • 1970-01-01
                • 2016-01-07
                • 2020-07-08
                • 2013-09-16
                • 1970-01-01
                • 2017-11-12
                相关资源
                最近更新 更多