在一个用户进程中存在标准输入(stdin
)、标准输出(stdout
)、标准错误(stderr
)三种流。Node.js中,对日志的操作是基于stdout
、stderr
两种流,如:console.log
方法是向stdout
写入数据,console.error
是向stderr
写入数据。通过stdout
和stderr
,或实现自定义Console
对象,可以将普通日志及错误日志分别写入到不同的文件中。
1. Console
类及console
对象
1.1 console
对象
console
对象是Node.js全局对象之一,它是一个Console
类的实例。该对象中包含以下方法,可以将日志数据分别写入stdout
和stderr
:
console.log
:向stdout
写入一行数据,console.info
是其别名方法console.error
:向stderr
写入一行数据,console.warn
是其别名方法
1.2 Console
类
Console
类有以下两种访问方式,自定义Console
类实例中同样有console.log
、console.error
等方法。
通过console
获取Console
类:
// 自定义 Console 实例 const myConsole = new console.Console(process.stdin, process.stderr); // 向 stdin 写入数据 myConsole.log('hello world'); // 向 stderr 写入数据 myConsole.error(new Error('Whoops, something bad happened'));
通过require('console')
获取Console
类:
const Console = require('console').Console; // 自定义 Console 实例 const myConsole = new Console(process.stdin, process.stderr); // 向 stdin 写入数据 myConsole.log('hello world'); // 向 stderr 写入数据 myConsole.error(new Error('Whoops, something bad happened'));
2. 基于进程对象process
将日志、错误写入不同文件
process
同样是一个全局对象,它提供了对标准流的访问接口。而process.stdout
和process.stderr
都是可写流,要将process.stdout
和process.stderr
中的数据写入不同的文件,首先需要将其转换为一个可读流或双工流:
const fs = require('fs'); const stream = require('stream'); const rawStdout = process.stdout; const rawStderr = process.stderr; // 创建一个PassThrough流 const newStdout = new stream.PassThrough(); const newStderr = new stream.PassThrough(); // 重新定义 process.stdout 的Getter process.__defineGetter__('stdout',function(){ // 原样返回 PassThrough return newStdout; }); // 重新定义 process.stderr 的Getter process.__defineGetter__('stderr',function(){ // 原样返回 PassThrough return newStderr; }); // 将 process.stdout 中的数据写入 stdout.log 文件 newStdout.pipe(fs.createWriteStream('./stdout.log')); // 将 process.stderr 中的数据写入 stderr.log 文件 newStderr.pipe(fs.createWriteStream('./stderr.log')); console.log('向 stdout 中写入数据'); console.error('向 stderr 中写入数据');
在上面我们通过定义stdout
和stderr
的访问器(Getter
),将其重新实现为一个PassThrough
流,并通过这个流将标准输出和标准错误中的数据分别写入了不同的文件。
注意:PassThrough
是一种特殊的Transform
,它会将写入的数据原样输出,而Transform
同时又是一个双工流。
3. 基于自定义Console
实例将日志、错误写入不同文件
Console
类的构造函数结构如下:
new Console(stdout[, stderr])
其构造函数中包含一个标准输出和一个可选的标准错误参数。全局console
对象的构造如下:
new Console(process.stdout, process.stderr);
要实现日志、错误写入不同文件,创建自定义Console
并将两个文件流参数传入构造函数即可:
const fs = require('fs'); const output = fs.createWriteStream('./stdout.log'); const errorOutput = fs.createWriteStream('./stderr.log'); // 自定义日志打印 var logger = new console.Console(output, errorOutput); logger.log('向 stdout 中写入数据'); logger.error('向 stderr 中写入数据');
这样就通过自定义Console
对象将日志、错误写入了不同的文件。要全局使用这个自定义对象,将其添加到Global对象,并使用logger
代替console
即可。