将Node.js配置为记录到文件而不是控制台

我可以配置console.log,以便日志被写入一个文件,而不是打印在控制台中吗?

371900 次浏览

Update 2013 -这是在Node v0.2和v0.4左右编写的;现在有关于日志的更好的实用程序。我强烈推荐温斯顿

Update 2013年底-我们仍然使用温斯顿,但现在有一个记录器库来包装自定义对象和格式的日志记录功能。下面是logger.js https://gist.github.com/rtgibbons/7354879的示例


应该就是这么简单。

var access = fs.createWriteStream(dir + '/node.access.log', { flags: 'a' })
, error = fs.createWriteStream(dir + '/node.error.log', { flags: 'a' });


// redirect stdout / stderr
proc.stdout.pipe(access);
proc.stderr.pipe(error);

如果这是针对应用程序的,那么最好使用日志记录模块。这会给你更多的灵活性。一些建议。

如果你正在寻找生产中的东西温斯顿可能是最好的选择。

如果你只是想快速完成开发工作,直接输出到文件中(我认为这只适用于*nix系统):

nohup node simple-server.js > output.log &

你现在可以使用毛毛虫,它是一个基于流的日志记录系统,允许你记录它,然后将输出输出到不同的转换和位置。

输出到一个文件很简单:

var logger = new (require('./').Logger)();
logger.pipe(require('fs').createWriteStream('./debug.log'));
logger.log('your log message');

卡特彼勒的网站上的完整示例

你也可以重载默认的console.log函数:

var fs = require('fs');
var util = require('util');
var log_file = fs.createWriteStream(__dirname + '/debug.log', {flags : 'w'});
var log_stdout = process.stdout;


console.log = function(d) { //
log_file.write(util.format(d) + '\n');
log_stdout.write(util.format(d) + '\n');
};

上面的例子将记录到debug.log和stdout。

编辑: 参见Clément的多参数版本也在本页。

我经常使用许多参数console.log ()console.error (),所以我的解决方案是:

var fs = require('fs');
var util = require('util');
var logFile = fs.createWriteStream('log.txt', { flags: 'a' });
// Or 'w' to truncate the file every time the process starts.
var logStdout = process.stdout;


console.log = function () {
logFile.write(util.format.apply(null, arguments) + '\n');
logStdout.write(util.format.apply(null, arguments) + '\n');
}
console.error = console.log;

重写console.log是正确的方法。但是要让它在所需的模块中工作,还需要导出它。

module.exports = console;

为了节省自己写日志文件的麻烦,旋转和东西,你可以考虑使用一个简单的记录器模块,如温斯顿:

// Include the logger module
var winston = require('winston');
// Set up log file. (you can also define size, rotation etc.)
winston.add(winston.transports.File, { filename: 'somefile.log' });
// Overwrite some of the build-in console functions
console.error = winston.error;
console.log = winston.info;
console.info = winston.info;
console.debug = winston.debug;
console.warn = winston.warn;
module.exports = console;
你也可以看看这个npm模块: https://www.npmjs.com/package/noogger < / p >

< a href = " http://xsmael.github。Io /noogger/" rel="nofollow noreferrer">noogger .

简单直接……

温斯顿是一个非常流行的用于日志记录的npm模块。

这是一个如何操作 在你的项目中安装winston:

npm install winston --save

这里有一个现成的配置,我经常在我的项目中使用它作为utils下的logger.js。

 /**
* Configurations of logger.
*/
const winston = require('winston');
const winstonRotator = require('winston-daily-rotate-file');


const consoleConfig = [
new winston.transports.Console({
'colorize': true
})
];


const createLogger = new winston.Logger({
'transports': consoleConfig
});


const successLogger = createLogger;
successLogger.add(winstonRotator, {
'name': 'access-file',
'level': 'info',
'filename': './logs/access.log',
'json': false,
'datePattern': 'yyyy-MM-dd-',
'prepend': true
});


const errorLogger = createLogger;
errorLogger.add(winstonRotator, {
'name': 'error-file',
'level': 'error',
'filename': './logs/error.log',
'json': false,
'datePattern': 'yyyy-MM-dd-',
'prepend': true
});


module.exports = {
'successlog': successLogger,
'errorlog': errorLogger
};

然后在需要的地方导入,如下所示:

const errorLog = require('../util/logger').errorlog;
const successlog = require('../util/logger').successlog;

然后您可以将成功记录为:

successlog.info(`Success Message and variables: ${variable}`);

错误为:

errorlog.error(`Error Message : ${error}`);

它还将所有的成功日志和错误日志记录在logs目录下的文件中,就像你在这里看到的那样 log direcotry < / p >

另一个没有提到的解决方案是在process.stdoutprocess.stderr中钩住Writable流。这样你就不需要重写输出到stdout和stderr的所有控制台功能。这个实现将stdout和stderr重定向到一个日志文件:

var log_file = require('fs').createWriteStream(__dirname + '/log.txt', {flags : 'w'})


function hook_stream(stream, callback) {
var old_write = stream.write


stream.write = (function(write) {
return function(string, encoding, fd) {
write.apply(stream, arguments)  // comments this line if you don't want output in the console
callback(string, encoding, fd)
}
})(stream.write)


return function() {
stream.write = old_write
}
}


console.log('a')
console.error('b')


var unhook_stdout = hook_stream(process.stdout, function(string, encoding, fd) {
log_file.write(string, encoding)
})


var unhook_stderr = hook_stream(process.stderr, function(string, encoding, fd) {
log_file.write(string, encoding)
})


console.log('c')
console.error('d')


unhook_stdout()
unhook_stderr()


console.log('e')
console.error('f')

它应该打印在控制台中

a
b
c
d
e
f

在日志文件中:

c
d

有关更多信息,请检查要点

const fs = require("fs");
const {keys} = Object;
const {Console} = console;


/**
* Redirect console to a file.  Call without path or with false-y
* value to restore original behavior.
* @param {string} [path]
*/
function file(path) {
const con = path ? new Console(fs.createWriteStream(path)) : null;


keys(Console.prototype).forEach(key => {
if (path) {
this[key] = (...args) => con[key](...args);
} else {
delete this[key];
}
});
};


// patch global console object and export
module.exports = console.file = file;

要使用它,可以这样做:

require("./console-file");
console.file("/path/to.log");
console.log("write to file!");
console.error("also write to file!");
console.file();    // go back to writing to stdout

直接从nodejs的API文档控制台

const output = fs.createWriteStream('./stdout.log');
const errorOutput = fs.createWriteStream('./stderr.log');
// custom simple logger
const logger = new Console(output, errorOutput);
// use it like console
const count = 5;
logger.log('count: %d', count);
// in stdout.log: count 5

我采用了将输出流交换为我的流的想法。

const LogLater                = require ('./loglater.js');
var logfile=new LogLater( 'log'+( new Date().toISOString().replace(/[^a-zA-Z0-9]/g,'-') )+'.txt' );




var PassThrough = require('stream').PassThrough;


var myout= new PassThrough();
var wasout=console._stdout;
myout.on('data',(data)=>{logfile.dateline("\r\n"+data);wasout.write(data);});
console._stdout=myout;


var myerr= new PassThrough();
var waserr=console._stderr;
myerr.on('data',(data)=>{logfile.dateline("\r\n"+data);waserr.write(data);});
console._stderr=myerr;

loglater.js:

const fs = require('fs');


function LogLater(filename, noduplicates, interval) {
this.filename = filename || "loglater.txt";
this.arr = [];
this.timeout = false;
this.interval = interval || 1000;
this.noduplicates = noduplicates || true;
this.onsavetimeout_bind = this.onsavetimeout.bind(this);
this.lasttext = "";
process.on('exit',()=>{ if(this.timeout)clearTimeout(this.timeout);this.timeout=false; this.save(); })
}


LogLater.prototype = {
_log: function _log(text) {
this.arr.push(text);
if (!this.timeout) this.timeout = setTimeout(this.onsavetimeout_bind, this.interval);
},
text: function log(text, loglastline) {
if (this.noduplicates) {
if (this.lasttext === text) return;
this.lastline = text;
}
this._log(text);
},
line: function log(text, loglastline) {
if (this.noduplicates) {
if (this.lasttext === text) return;
this.lastline = text;
}
this._log(text + '\r\n');
},
dateline: function dateline(text) {
if (this.noduplicates) {
if (this.lasttext === text) return;
this.lastline = text;
}
this._log(((new Date()).toISOString()) + '\t' + text + '\r\n');
},
onsavetimeout: function onsavetimeout() {
this.timeout = false;
this.save();
},
save: function save() { fs.appendFile(this.filename, this.arr.splice(0, this.arr.length).join(''), function(err) { if (err) console.log(err.stack) }); }
}


module.exports = LogLater;

改进安德烈斯·里奥里奥,处理任何数量的争论

var fs = require('fs');
var util = require('util');


var log_file = fs.createWriteStream(__dirname + '/debug.log', {flags : 'w'});
var log_stdout = process.stdout;


console.log = function(...args) {
var output = args.join(' ');
log_file.write(util.format(output) + '\r\n');
log_stdout.write(util.format(output) + '\r\n');
};

我只是建立了一个包来做这个,希望你喜欢它;) https://www.npmjs.com/package/writelog < / p >

我自己简单地从温斯顿的例子,并添加log(...)方法(因为温斯顿命名为info(..):

< >强Console.js:

"use strict"


// Include the logger module
const winston = require('winston');


const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});


//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}


// Add log command
logger.log=logger.info;


module.exports = logger;
然后在代码中简单地使用:

const console = require('Console')

现在你可以简单地在你的文件中使用正常的日志功能,它会创建一个文件并将其记录到你的控制台(在调试/开发时)。因为if (process.env.NODE_ENV !== 'production') {(以防你也想在生产中使用它)…

对于简单的情况,我们可以使用“在”' 2祝辞,1 '标准输出(STDOUT)和标准错误(STDERR)流直接重定向到一个文件(例如,test.log)

例子:

// test.js
(function() {
// Below outputs are sent to Standard Out (STDOUT) stream
console.log("Hello Log");
console.info("Hello Info");
// Below outputs are sent to Standard Error (STDERR) stream
console.error("Hello Error");
console.warn("Hello Warning");
})();

节点test.js >test.log 2祝辞,1

根据POSIX标准," input " " output "和" error "流由正整数< >强文件描述符< / >强(0,1,2)标识,即Stdin为0,stdout为1,stderr为2。

步骤1:' 2祝辞,1 '将从2 (< >强stderr < / >强)重定向到1 (< >强stdout < / >强)

第2步:“在”将从1 (< >强stdout < / >强)重定向到文件(< >强test.log < / >强)

方法stdout和stderr

这种方法可以帮助你(我在我的项目中使用类似的方法),适用于包括console.log,控制台。警告说,控制台。错误,console.info在内的所有方法

该方法将写入stdout和stderr的字节写入文件。比更改console.log, console.log更好。警告说,控制台。错误,console.info方法,因为输出将与此方法的输出完全相同


var fs= require("fs")
var os= require("os")
var HOME= os.homedir()
var stdout_r = fs.createWriteStream(HOME + '/node.stdout.log', { flags: 'a' })
var stderr_r = fs.createWriteStream(HOME + '/node.stderr.log', { flags: 'a' })


var attachToLog= function(std, std_new){


var originalwrite= std.write
std.write= function(data,enc){
try{
var d= data
if(!Buffer.isBuffer(d))
d= Buffer.from(data, (typeof enc === 'string') ? enc : "utf8")
std_new.write.apply(std_new, d)
}catch(e){}
return originalwrite.apply(std, arguments)
}




}
attachToLog(process.stdout, stdout_r)
attachToLog(process.stderr, stderr_r)


// recommended catch error on stdout_r and stderr_r
// stdout_r.on("error", yourfunction)
// stderr_r.on("error", yourfunction)

对于未来的用户。@keshavDulal 回答不适用于最新版本。我找不到一个适当的修复问题,报告在最新版本3.3.3

不管怎样,在研究了一下之后,我终于把它修好了。下面是温斯顿版本3.3.3的解决方案

安装winston和winston-daily-rotate-file

npm install winston
npm install winston-daily-rotate-file

创建一个新文件utils/logger.js

const winston = require('winston');
const winstonRotator = require('winston-daily-rotate-file');


var logger = new winston.createLogger({
transports: [
new (winston.transports.DailyRotateFile)({
name: 'access-file',
level: 'info',
filename: './logs/access.log',
json: false,
datePattern: 'yyyy-MM-DD',
prepend: true,
maxFiles: 10
}),
new (winston.transports.DailyRotateFile)({
name: 'error-file',
level: 'error',
filename: './logs/error.log',
json: false,
datePattern: 'yyyy-MM-DD',
prepend: true,
maxFiles: 10
})
]
});




module.exports = {
logger
};

然后在任何你想要使用日志导入模块的文件

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

像下面这样使用记录器:

logger.info('Info service started');
logger.error('Service crashed');

如果您正在使用linux,您还可以使用输出重定向。Windows就不太确定了。

node server.js >> file.log 2>> file.log

>> file.log重定向到文件

2>> file.log重定向到文件

其他人使用缩写&>>来表示stdoutstderr,但它不被我的mac和ubuntu所接受:(

额外的: >覆盖,而>>追加。

顺便说一下,关于NodeJS记录器,我使用pino + pino-pretty记录器

除了上面的答案,对覆盖console.log的简短而有效的代码进行了一点扩展。小增加:设置文件名与日期,包装功能,也做原来的控制台。日志记录以保持控制台使用该信息处于活动状态。

用法:在代码的开头,运行setConsoleLogToFile([FILENAME])

const fs = require("fs"),
util = require('util');




const getPrettyDate = ()=> new Date().toString().replace(":","-").replace(/00\s\(.*\)/, "").replace(` ${new Date().getFullYear()}`, ",").replace(/:\d\d\s/, " ");


module.exports.getPrettyDate = getPrettyDate;


module.exports.setConsoleLogToFile = (filename) => {
const log_file = fs.createWriteStream(`${__dirname}/${filename} -  ${getPrettyDate()}.log`, { flags: 'w' }),
log_stdout = process.stdout;


const origConsole = console.log;
console.log = (d) => {
origConsole(d);
log_file.write(util.format(d) + '\n');
log_stdout.write(util.format(d) + '\n');
};
}

大多数记录器是过量的,不支持console.log中的正确构建。因此我创建了console-log-to-file:

import { consoleLogToFile } from "console-log-to-file";
// or `const { consoleLogToFile } = require("console-log-to-file/dist/index.cjs.js")`


consoleLogToFile({
logFilePath: "/log/default.log",
});


// all of your console.log/warn/error/info will work as it does and save to file now.

如果你正在使用永远来保持节点应用程序运行,那么输入forever list将显示console.log正在写入的日志文件的路径

enter image description here

如果你正在寻找一个解决方案无需修改任何代码,这里有一个简单的解决方案。

它需要pm2,只需将它添加到你的节点模块和启动你的应用程序

pm2 start server.js

你完成了,控制台。日志现在在家庭/ .pm2 /日志/ server-out.log下注册为自动

创建一个utils/logger.js文件:

var fs = require('fs');
var util = require('util');
var log_file = fs.createWriteStream(__dirname + '/../logs/server.log', { flags: 'w' });
var log_stdout = process.stdout;


console.log = function () { //
[...arguments].forEach(element => {
log_file.write(util.format(element) + '\n');
log_stdout.write(util.format(element) + '\n');
});
};


module.exports = {
console
}

将logger.js文件包含在你想要console.log的任何文件中,例如:

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

创建一个logs文件夹,并在其中创建一个空的server.log文件,并运行你的应用程序:)

基于多参数版本由Clément,只是文本文件没有颜色代码

var fs = require('fs');
var util = require('util');
var logFile = fs.createWriteStream('log.txt', { flags: 'a' });
// Or 'w' to truncate the file every time the process starts.
var logStdout = process.stdout;


console.log = function () {
// Storing without color codes
logFile.write(util.format.apply(null,arguments).replace(/\033\[[0-9;]*m/g,"") + '\n');
// Display normally, with colors to Stdout
logStdout.write(util.format.apply(null, arguments) + '\n');
}

注:回答因为我不能评论

Rudy Huynh的解决方案对我来说非常有效。我添加了一点,让它吐出带有今天日期和时间的文件。

var dateNow = new Date();
var timeNow = dateNow.getHours() + '-' + dateNow.getMinutes();
var logPath = "log/" + dateNow.toDateString() + ' -' + ' Start Time - ' + timeNow + ".log"


consoleLogToFile({
logFilePath: logPath
});

它不是很优雅,但这样它将保存不同的,易于阅读的日志文件,而不是只是更新相同的“;default.log"文件。