为所有控制台消息添加时间戳

时间:2013-09-15 15:42:41

标签: node.js express console

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

这一切都运行得很好,但现在我错过了时间戳 - 确切地知道错误发生的时间。

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

有没有办法,也许是Express中间件,可以让我为每次调用添加时间戳,还是我必须手动添加它?

11 个答案:

答案 0 :(得分:98)

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

为了记录,我安装了模块console-stamp(npm 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格式,而不是我在其他控制台调用中使用的格式。通过注册我自己的时间格式可以很容易地解决这个问题(作为副作用,需要dateformat模块console stamp,而不是安装另一个模块):

// 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
...

答案 1 :(得分:23)

使用以下内容创建文件:

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

答案 2 :(得分:9)

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

答案 3 :(得分:8)

如果您想要一个没有其他外部依赖关系的解决方案但想要保留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

答案 4 :(得分:3)

app.use(morgan('[:date[web]] :method :url :status :res[content-length] - :remote-addr - :response-time ms'))

答案 5 :(得分:2)

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

"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);

答案 6 :(得分:1)

这不是一个直接的答案,但你有没有看过winston.js?它有更多的日志记录选项,包括记录到json文件或数据库。默认情况下,它们始终具有时间戳。只是一个想法。

答案 7 :(得分:1)

您可以使用https://nodejs.org/api/util.html中的util.log功能。

答案 8 :(得分:1)

这个实现很简单,支持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 );
};

答案 9 :(得分:1)

我正在尝试覆盖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呼叫。

答案 10 :(得分:0)

像这样使用事件监听器,

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

快乐的编码:)