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

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

这一切工作得很好,但是现在我缺少时间戳——无法准确地知道错误发生的时间。

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

有没有一种方法,也许是 Express 中间件,可以让我为每个电话添加一个时间戳,还是我必须手动添加它?

124727 次浏览

这不是个直接的答案,但你查过 Winston Js 吗?它有大量的日志记录选项,包括对 json 文件或数据库的日志记录。默认情况下,它们总是有时间戳。只是个想法。

创建包含以下内容的文件:

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 文件顶部的控制台函数,并让它在其他每个模块中生效。我得到了好坏参半的结果,因为我的一个模块是分叉的 child_process。一旦我将该行复制到该文件的顶部,所有工作。

为了便于记录,我安装了模块 控制台标记(npm install console-stamp --save) ,并将这一行添加到 app.js 和 children Process.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
...

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

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

对于更高的版本,你应该 “使用第三方模块代替。”

你也可以使用 日志时间戳软件包,它非常简单,也是可定制的。

如果你想要一个没有其他外部依赖的解决方案,但是你想保留 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));
};

您可以修改 format Console Date 函数,以按照需要的方式格式化日期。

这段代码只需要在您的主 JavaScript 文件上编写一次。

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

[12:22:55.053] hey

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

The module 日志时间戳 works for me.

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
app.use(morgan('[:date[web]] :method :url :status :res[content-length] - :remote-addr - :response-time ms'))

像这样使用事件侦听器,

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

快乐编码:)

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

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

After that, you may use it in your code as :

const logger = require('./logger');


logger.log('hello world', 123456);
logger.error('some error occurred', err);

I'm trying overwriting the console object - seems to be working well. To use, save the code below in a file, and then import to overwrite the proxy object, and then use as normal.

(注意,这需要巴贝尔翻译,并且不能在不支持 JavaScriptProxy构造函数的环境中工作,比如 IE11)。

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等时,覆盖控制台将检查您所调用的是否是函数,如果是,它将在 log 语句中注入一个日期作为第一个参数,然后是所有参数。

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

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

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 等。

一个适合2022年的答案

const log = console.log;


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