winston 中文网
几乎所有内容的日志器。
¥A logger for just about everything.
winston@3
有关更多信息,请参阅 升级指南。欢迎提交错误报告和 PR!
¥See the Upgrade Guide for more information. Bug reports and PRs welcome!
正在寻找 winston@2.x
文档?
¥Looking for winston@2.x
documentation?
请注意,以下文档适用于 winston@3
。阅读 winston@2.x
文档。
¥Please note that the documentation below is for winston@3
.
Read the winston@2.x
documentation.
动机
¥Motivation
winston
旨在成为一个简单且通用的日志库,支持多种传输。传输本质上是日志的存储设备。每个 winston
日志器都可以在不同级别配置多个传输(参见:传输)(参见:日志级别).例如,可能希望将错误日志存储在持久的远程位置(如数据库),但所有日志都输出到控制台或本地文件。
¥winston
is designed to be a simple and universal logging library with
support for multiple transports. A transport is essentially a storage device
for your logs. Each winston
logger can have multiple transports (see:
Transports) configured at different levels (see: Logging levels). For
example, one may want error logs to be stored in a persistent remote location
(like a database), but all logs output to the console or a local file.
winston
旨在解耦日志记录过程的各个部分,使其更加灵活和可扩展。注意支持日志格式的灵活性(参见:格式)和级别(参见:使用自定义日志级别),并确保这些 API 与传输日志的实现分离(即日志的存储/索引方式,请参阅:添加自定义传输) 到他们向程序员公开的 API。
¥winston
aims to decouple parts of the logging process to make it more
flexible and extensible. Attention is given to supporting flexibility in log
formatting (see: Formats) & levels (see: Using custom logging levels), and
ensuring those APIs decoupled from the implementation of transport logging
(i.e. how the logs are stored / indexed, see: Adding Custom Transports) to
the API that they exposed to the programmer.
快速入门
¥Quick Start
TL;DR?查看 ./examples/
中的 快速入门示例。./examples/*.js
中有许多其他示例。没有看到你认为应该存在的示例?提交拉取请求以添加它!
¥TL;DR? Check out the quick start example in ./examples/
.
There are a number of other examples in ./examples/*.js
.
Don't see an example you think should be there? Submit a pull request
to add it!
用法
¥Usage
使用 winston
的推荐方法是创建自己的日志器。最简单的方法是使用 winston.createLogger
:
¥The recommended way to use winston
is to create your own logger. The
simplest way to do this is using winston.createLogger
:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'user-service' },
transports: [
//
// - Write all logs with importance level of `error` or higher to `error.log`
// (i.e., error, fatal, but not other levels)
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
//
// - Write all logs with importance level of `info` or higher to `combined.log`
// (i.e., fatal, error, warn, and info, but not trace)
//
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(),
}));
}
你也可以直接通过 require('winston')
公开的默认日志器进行记录,但这仅仅是一个如果你愿意,可以在整个应用中使用方便的共享日志器。请注意,默认日志器默认没有任何传输。你需要自己添加传输,并且保留默认日志器而不使用任何传输可能会产生高内存使用率问题。
¥You may also log directly via the default logger exposed by
require('winston')
, but this merely intended to be a convenient shared
logger to use throughout your application if you so choose.
Note that the default logger doesn't have any transports by default.
You need add transports by yourself, and leaving the default logger without any
transports may produce a high memory usage issue.
目录
¥Table of contents
日志记录
¥Logging
winston
中的日志记录级别符合 RFC5424 指定的严重性顺序:假定所有级别的严重性都按数字从最重要到最不重要的顺序递增。
¥Logging levels in winston
conform to the severity ordering specified by
RFC5424: severity of all levels is assumed to be numerically ascending
from most important to least important.
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
verbose: 4,
debug: 5,
silly: 6
};
创建你自己的日志器
¥Creating your own Logger
你可以通过使用 winston.createLogger
创建日志器开始:
¥You get started by creating a logger using winston.createLogger
:
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' })
]
});
日志器接受以下参数:
¥A logger accepts the following parameters:
名称 | 默认 | 描述 |
---|---|---|
level | 'info' | 仅当 info.level 小于或等于此级别时才记录 |
levels | winston.config.npm.levels | 表示日志优先级的级别(和颜色) |
format | winston.format.json | info 消息的格式(参见:[格式]) |
transports | [] (无传输) | info 消息的日志记录目标集 |
exitOnError | true | 如果为 false,则处理的异常不会导致 process.exit |
silent | false | 如果为 true,则所有日志都将被抑制 |
提供给 createLogger
的级别将定义为返回的 logger
上的便捷方法。
¥The levels provided to createLogger
will be defined as convenience methods
on the logger
returned.
//
// Logging
//
logger.log({
level: 'info',
message: 'Hello distributed log files!'
});
logger.info('Hello again distributed logs');
一旦 winston.createLogger
向你提供了传输,你就可以从 logger
中添加或删除传输:
¥You can add or remove transports from the logger
once it has been provided
to you from winston.createLogger
:
const files = new winston.transports.File({ filename: 'combined.log' });
const console = new winston.transports.Console();
logger
.clear() // Remove all transports
.add(console) // Add console transport
.add(files) // Add file transport
.remove(console); // Remove console transport
你还可以使用 configure
方法批量重新配置 winston.Logger
实例:
¥You can also wholesale reconfigure a winston.Logger
instance using the
configure
method:
const logger = winston.createLogger({
level: 'info',
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' })
]
});
//
// Replaces the previous transports with those in the
// new configuration wholesale.
//
const DailyRotateFile = require('winston-daily-rotate-file');
logger.configure({
level: 'verbose',
transports: [
new DailyRotateFile(opts)
]
});
创建子日志器
¥Creating child loggers
你可以从现有日志器创建子日志器以传递元数据覆盖:
¥You can create child loggers from existing loggers to pass metadata overrides:
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
]
});
const childLogger = logger.child({ requestId: '451' });
如果你还扩展了
Logger
类,则.child
可能会出现错误,因为某些实现细节会使this
关键字指向意外的东西。请谨慎使用。¥
.child
is likely to be bugged if you're also extending theLogger
class, due to some implementation details that makethis
keyword to point to unexpected things. Use with caution.
流、objectMode
和 info
对象
¥Streams, objectMode
, and info
objects
在 winston
中,Logger
和 Transport
实例都被视为接受 info
对象的 objectMode
流。
¥In winston
, both Logger
and Transport
instances are treated as
objectMode
streams that accept an info
object.
提供给给定格式的 info
参数代表单个日志消息。对象本身是可变的。每个 info
必须至少具有 level
和 message
属性:
¥The info
parameter provided to a given format represents a single log
message. The object itself is mutable. Every info
must have at least the
level
and message
properties:
const info = {
level: 'info', // Level of the logging message
message: 'Hey! Log something?' // Descriptive message being logged.
};
除了级别和消息之外的属性被视为“meta
”。即:
¥Properties besides level and message are considered as "meta
". i.e.:
const { level, message, ...meta } = info;
logform
本身的几种格式添加了附加属性:
¥Several of the formats in logform
itself add additional properties:
属性 | 格式由 | 描述 |
---|---|---|
splat | splat() | %d %s 样式消息的字符串插值 splat。 |
timestamp | timestamp() | 收到消息的时间戳。 |
label | label() | 与每个关联的自定义标签消息。 |
ms | ms() | 自上一条日志消息以来的毫秒数。 |
作为消费者,你可以添加任何你想要的属性 - 内部状态由 Symbol
属性维护:
¥As a consumer you may add whatever properties you wish – internal state is
maintained by Symbol
properties:
-
Symbol.for('level')
(READ-ONLY):等于level
属性。被所有代码视为不可变的。¥
Symbol.for('level')
(READ-ONLY): equal tolevel
property. Is treated as immutable by all code. -
"最终确定格式" 设置的完整字符串消息:
¥
Symbol.for('message'):
complete string message set by "finalizing formats":-
json
-
logstash
-
printf
-
prettyPrint
-
simple
-
-
Symbol.for('splat')
:其他字符串插值参数。仅由splat()
格式使用。¥
Symbol.for('splat')
: additional string interpolation arguments. Used exclusively bysplat()
format.
这些符号存储在另一个包中:triple-beam
以便所有 logform
的使用者都可以拥有相同的符号引用。即:
¥These Symbols are stored in another package: triple-beam
so that all
consumers of logform
can have the same Symbol reference. i.e.:
const { LEVEL, MESSAGE, SPLAT } = require('triple-beam');
console.log(LEVEL === Symbol.for('level'));
// true
console.log(MESSAGE === Symbol.for('message'));
// true
console.log(SPLAT === Symbol.for('splat'));
// true
注意:提供的
meta
对象中的任何{ message }
属性将自动连接到任何已提供的msg
:例如,以下内容将 'world' 连接到 'hello':¥NOTE: any
{ message }
property in ameta
object provided will automatically be concatenated to anymsg
already provided: For example the below will concatenate 'world' onto 'hello':logger.log('error', 'hello', { message: 'world' });
logger.info('hello', { message: 'world' });
格式
¥Formats
可以从 winston.format
访问 winston
中的格式。它们是在 logform
中实现的,logform
是独立于 winston
的模块。如果你希望在传输中包含默认格式,这可以让你在编写自己的传输时具有灵活性。
¥Formats in winston
can be accessed from winston.format
. They are
implemented in logform
, a separate
module from winston
. This allows flexibility when writing your own transports
in case you wish to include a default format with your transport.
在现代版本的 node
中,模板字符串非常高效,是进行大多数终端用户格式化的推荐方式。如果你想定制日志格式,winston.format.printf
适合你:
¥In modern versions of node
template strings are very performant and are the
recommended way for doing most end-user formatting. If you want to bespoke
format your logs, winston.format.printf
is for you:
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, label, printf } = format;
const myFormat = printf(({ level, message, label, timestamp }) => {
return `${timestamp} [${label}] ${level}: ${message}`;
});
const logger = createLogger({
format: combine(
label({ label: 'right meow!' }),
timestamp(),
myFormat
),
transports: [new transports.Console()]
});
要查看可用的内置格式并了解有关创建自己的自定义日志格式的更多信息,请参阅 logform
。
¥To see what built-in formats are available and learn more about creating your
own custom logging formats, see logform
.
组合格式
¥Combining formats
可以使用 format.combine
将任意数量的格式组合成一种格式。由于 format.combine
不接受 opts
,为了方便起见,它会返回组合格式的预先创建的实例。
¥Any number of formats may be combined into a single format using
format.combine
. Since format.combine
takes no opts
, as a convenience it
returns pre-created instance of the combined format.
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, label, prettyPrint } = format;
const logger = createLogger({
format: combine(
label({ label: 'right meow!' }),
timestamp(),
prettyPrint()
),
transports: [new transports.Console()]
})
logger.log({
level: 'info',
message: 'What time is the testing at?'
});
// Outputs:
// { level: 'info',
// message: 'What time is the testing at?',
// label: 'right meow!',
// timestamp: '2017-09-30T03:57:26.875Z' }
字符串插值
¥String interpolation
log
方法使用 util.format 提供字符串插值。必须使用 format.splat()
启用它。
¥The log
method provides the string interpolation using util.format. It
must be enabled using format.splat()
.
下面是一个示例,它使用 format.splat
定义带有消息字符串插值的格式,然后使用 format.simple
序列化整个 info
消息。
¥Below is an example that defines a format with string interpolation of
messages using format.splat
and then serializes the entire info
message
using format.simple
.
const { createLogger, format, transports } = require('winston');
const logger = createLogger({
format: format.combine(
format.splat(),
format.simple()
),
transports: [new transports.Console()]
});
// info: test message my string {}
logger.log('info', 'test message %s', 'my string');
// info: test message 123 {}
logger.log('info', 'test message %d', 123);
// info: test message first second {number: 123}
logger.log('info', 'test message %s, %s', 'first', 'second', { number: 123 });
过滤 info
对象
¥Filtering info
Objects
如果你希望在记录时完全过滤掉给定的 info
对象,则只需返回一个 falsey 值。
¥If you wish to filter out a given info
Object completely when logging then
simply return a falsey value.
const { createLogger, format, transports } = require('winston');
// Ignore log messages if they have { private: true }
const ignorePrivate = format((info, opts) => {
if (info.private) { return false; }
return info;
});
const logger = createLogger({
format: format.combine(
ignorePrivate(),
format.json()
),
transports: [new transports.Console()]
});
// Outputs: {"level":"error","message":"Public error to share"}
logger.log({
level: 'error',
message: 'Public error to share'
});
// Messages with { private: true } will not be written when logged.
logger.log({
private: true,
level: 'error',
message: 'This is super secret - hide it.'
});
使用 format.combine
将尊重任何返回的 falsey 值并停止评估系列中后续格式。例如:
¥Use of format.combine
will respect any falsey values return and stop
evaluation of later formats in the series. For example:
const { format } = require('winston');
const { combine, timestamp, label } = format;
const willNeverThrow = format.combine(
format(info => { return false })(), // Ignores everything
format(info => { throw new Error('Never reached') })()
);
创建自定义格式
¥Creating custom formats
格式是定义单个方法的原型对象(即类实例):transform(info, opts)
并返回修改的 info
:
¥Formats are prototypal objects (i.e. class instances) that define a single
method: transform(info, opts)
and return the mutated info
:
-
info
:表示日志消息的对象。¥
info
: an object representing the log message. -
opts
:特定于当前格式实例的设置。¥
opts
: setting specific to the current instance of the format.
它们预计会返回以下两项之一:
¥They are expected to return one of two things:
-
表示修改后的
info
参数的info
对象。如果希望不可变性,则无需保留对象引用。所有当前内置格式都认为info
是可变的,但 [immutablejs] 正在考虑用于未来版本。¥An
info
Object representing the modifiedinfo
argument. Object references need not be preserved if immutability is preferred. All current built-in formats considerinfo
mutable, but [immutablejs] is being considered for future releases. -
一个 falsey 值,表示调用者应忽略
info
参数。(参见:过滤info
对象)如下。¥A falsey value indicating that the
info
argument should be ignored by the caller. (See: Filteringinfo
Objects) below.
winston.format
的设计尽可能简单。要定义新格式,只需将其传递给 transform(info, opts)
函数即可获得新的 Format
。
¥winston.format
is designed to be as simple as possible. To define a new
format, simply pass it a transform(info, opts)
function to get a new
Format
.
返回的命名 Format
可用于根据需要创建给定 Format
的任意数量的副本:
¥The named Format
returned can be used to create as many copies of the given
Format
as desired:
const { format } = require('winston');
const volume = format((info, opts) => {
if (opts.yell) {
info.message = info.message.toUpperCase();
} else if (opts.whisper) {
info.message = info.message.toLowerCase();
}
return info;
});
// `volume` is now a function that returns instances of the format.
const scream = volume({ yell: true });
console.dir(scream.transform({
level: 'info',
message: `sorry for making you YELL in your head!`
}, scream.options));
// {
// level: 'info'
// message: 'SORRY FOR MAKING YOU YELL IN YOUR HEAD!'
// }
// `volume` can be used multiple times to create different formats.
const whisper = volume({ whisper: true });
console.dir(whisper.transform({
level: 'info',
message: `WHY ARE THEY MAKING US YELL SO MUCH!`
}, whisper.options));
// {
// level: 'info'
// message: 'why are they making us yell so much!'
// }
日志记录级别
¥Logging Levels
winston
中的日志记录级别符合 RFC5424 指定的严重性顺序:假定所有级别的严重性都按数字从最重要到最不重要的顺序递增。
¥Logging levels in winston
conform to the severity ordering specified by
RFC5424: severity of all levels is assumed to be numerically ascending
from most important to least important.
每个 level
都被赋予特定的整数优先级。优先级越高,消息被认为越重要,相应的整数优先级越低。例如,如 RFC5424 中所述,syslog
级别的优先级从 0 到 7(从高到低)。
¥Each level
is given a specific integer priority. The higher the priority the
more important the message is considered to be, and the lower the
corresponding integer priority. For example, as specified exactly in RFC5424
the syslog
levels are prioritized from 0 to 7 (highest to lowest).
{
emerg: 0,
alert: 1,
crit: 2,
error: 3,
warning: 4,
notice: 5,
info: 6,
debug: 7
}
同样,npm
日志记录级别的优先级从 0 到 6(从高到低):
¥Similarly, npm
logging levels are prioritized from 0 to 6 (highest to
lowest):
{
error: 0,
warn: 1,
info: 2,
http: 3,
verbose: 4,
debug: 5,
silly: 6
}
如果你没有明确定义 winston
应使用的级别,则将使用上面的 npm
级别。
¥If you do not explicitly define the levels that winston
should use, the
npm
levels above will be used.
使用日志记录级别
¥Using Logging Levels
可以通过两种方式之一设置日志记录消息的级别。你可以将表示日志记录级别的字符串传递给 log() 方法,或使用每个 winston Logger 上定义的级别指定方法。
¥Setting the level for your logging message can be accomplished in one of two ways. You can pass a string representing the logging level to the log() method or use the level specified methods defined on every winston Logger.
//
// Any logger instance
//
logger.log('silly', "127.0.0.1 - there's no place like home");
logger.log('debug', "127.0.0.1 - there's no place like home");
logger.log('verbose', "127.0.0.1 - there's no place like home");
logger.log('info', "127.0.0.1 - there's no place like home");
logger.log('warn', "127.0.0.1 - there's no place like home");
logger.log('error', "127.0.0.1 - there's no place like home");
logger.info("127.0.0.1 - there's no place like home");
logger.warn("127.0.0.1 - there's no place like home");
logger.error("127.0.0.1 - there's no place like home");
//
// Default logger
//
winston.log('info', "127.0.0.1 - there's no place like home");
winston.info("127.0.0.1 - there's no place like home");
winston
允许你在每个传输上定义一个 level
属性,该属性指定传输应记录的最大消息级别。例如,使用 syslog
级别,你可以只将 error
消息记录到控制台,将 info
及以下的所有内容记录到文件(包括 error
消息):
¥winston
allows you to define a level
property on each transport which
specifies the maximum level of messages that a transport should log. For
example, using the syslog
levels you could log only error
messages to the
console and everything info
and below to a file (which includes error
messages):
const logger = winston.createLogger({
levels: winston.config.syslog.levels,
transports: [
new winston.transports.Console({ level: 'error' }),
new winston.transports.File({
filename: 'combined.log',
level: 'info'
})
]
});
你还可以动态更改传输的日志级别:
¥You may also dynamically change the log level of a transport:
const transports = {
console: new winston.transports.Console({ level: 'warn' }),
file: new winston.transports.File({ filename: 'combined.log', level: 'error' })
};
const logger = winston.createLogger({
transports: [
transports.console,
transports.file
]
});
logger.info('Will not be logged in either transport!');
transports.console.level = 'info';
transports.file.level = 'info';
logger.info('Will be logged in both transports!');
winston
支持可自定义的日志记录级别,默认为 npm 样式的日志记录级别。必须在创建日志器时指定级别。
¥winston
supports customizable logging levels, defaulting to npm style
logging levels. Levels must be specified at the time of creating your logger.
使用自定义日志记录级别
¥Using Custom Logging Levels
除了 winston
中可用的预定义 npm
、syslog
和 cli
级别之外,你还可以选择定义自己的级别:
¥In addition to the predefined npm
, syslog
, and cli
levels available in
winston
, you can also choose to define your own:
const myCustomLevels = {
levels: {
foo: 0,
bar: 1,
baz: 2,
foobar: 3
},
colors: {
foo: 'blue',
bar: 'green',
baz: 'yellow',
foobar: 'red'
}
};
const customLevelLogger = winston.createLogger({
levels: myCustomLevels.levels
});
customLevelLogger.foobar('some foobar level-ed message');
虽然此数据结构中存在轻微重复,但如果你不想使用颜色,它可以实现简单的封装。如果你确实希望有颜色,除了将级别传递给 Logger 本身之外,还必须让 winston 知道它们:
¥Although there is slight repetition in this data structure, it enables simple encapsulation if you do not want to have colors. If you do wish to have colors, in addition to passing the levels to the Logger itself, you must make winston aware of them:
winston.addColors(myCustomLevels.colors);
这使使用 colorize
格式化程序的日志器能够适当地为自定义级别的输出着色和设置样式。
¥This enables loggers using the colorize
formatter to appropriately color and style
the output of custom levels.
此外,你还可以更改背景颜色和字体样式。例如,
¥Additionally, you can also change background color and font style. For example,
baz: 'italic yellow',
foobar: 'bold red cyanBG'
可能的选项如下。
¥Possible options are below.
-
字体样式:
bold
,dim
,italic
,underline
,inverse
,hidden
,strikethrough
.¥Font styles:
bold
,dim
,italic
,underline
,inverse
,hidden
,strikethrough
. -
字体前景色:
black
,red
,green
,yellow
,blue
,magenta
,cyan
,white
,gray
,grey
.¥Font foreground colors:
black
,red
,green
,yellow
,blue
,magenta
,cyan
,white
,gray
,grey
. -
背景颜色:
blackBG
,redBG
,greenBG
,yellowBG
,blueBG
magentaBG
,cyanBG
,whiteBG
¥Background colors:
blackBG
,redBG
,greenBG
,yellowBG
,blueBG
magentaBG
,cyanBG
,whiteBG
为标准日志级别着色
¥Colorizing Standard logging levels
要为标准日志级别着色,请添加
¥To colorize the standard logging level add
winston.format.combine(
winston.format.colorize(),
winston.format.simple()
);
其中 winston.format.simple()
是你想要使用的任何其他格式化程序。colorize
格式化程序必须位于添加你希望着色的文本的任何格式化程序之前。
¥where winston.format.simple()
is whatever other formatter you want to use. The colorize
formatter must come before any formatters adding text you wish to color.
使用 json 格式日志时为整行日志着色
¥Colorizing full log line when json formatting logs
要使用 json 格式化程序为整个日志行着色,你可以应用以下内容
¥To colorize the full log line with the json formatter you can apply the following
winston.format.combine(
winston.format.json(),
winston.format.colorize({ all: true })
);
传输
¥Transports
winston
中包含多个 核心传输,它们利用 Node.js 核心提供的内置网络和文件 I/O。此外,还有社区成员编写的 附加传输。
¥There are several core transports included in winston
, which leverage the
built-in networking and file I/O offered by Node.js core. In addition, there
are additional transports written by members of the community.
相同类型的多个传输
¥Multiple transports of the same type
在构建传输时,可以使用相同类型的多个传输,例如 winston.transports.File
。
¥It is possible to use multiple transports of the same type e.g.
winston.transports.File
when you construct the transport.
const logger = winston.createLogger({
transports: [
new winston.transports.File({
filename: 'combined.log',
level: 'info'
}),
new winston.transports.File({
filename: 'errors.log',
level: 'error'
})
]
});
如果你以后想要删除其中一个传输,你可以使用传输本身来执行此操作。例如:
¥If you later want to remove one of these transports you can do so by using the transport itself. e.g.:
const combinedLogs = logger.transports.find(transport => {
return transport.filename === 'combined.log'
});
logger.remove(combinedLogs);
添加自定义传输
¥Adding Custom Transports
添加自定义传输很容易。你需要做的就是接受你需要的任何选项,实现 log() 方法,然后使用 winston
使用它。
¥Adding a custom transport is easy. All you need to do is accept any options
you need, implement a log() method, and consume it with winston
.
const Transport = require('winston-transport');
const util = require('util');
//
// Inherit from `winston-transport` so you can take advantage
// of the base functionality and `.exceptions.handle()`.
//
module.exports = class YourCustomTransport extends Transport {
constructor(opts) {
super(opts);
//
// Consume any custom options here. e.g.:
// - Connection information for databases
// - Authentication information for APIs (e.g. loggly, papertrail,
// logentries, etc.).
//
}
log(info, callback) {
setImmediate(() => {
this.emit('logged', info);
});
// Perform the writing to the remote service
callback();
}
};
常见传输选项
¥Common Transport options
由于每个传输都从 winston-transport 继承,因此可以分别在每个传输上设置自定义格式和自定义日志级别:
¥As every transport inherits from winston-transport, it's possible to set a custom format and a custom log level on each transport separately:
const logger = winston.createLogger({
transports: [
new winston.transports.File({
filename: 'error.log',
level: 'error',
format: winston.format.json()
}),
new winston.transports.Http({
level: 'warn',
format: winston.format.json()
}),
new winston.transports.Console({
level: 'info',
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
})
]
});
异常
¥Exceptions
使用 winston 处理未捕获的异常
¥Handling Uncaught Exceptions with winston
使用 winston
,可以从你的进程中捕获和记录 uncaughtException
事件。使用你自己的日志器实例,你可以在创建时或在应用生命周期的稍后启用此行为:
¥With winston
, it is possible to catch and log uncaughtException
events
from your process. With your own logger instance you can enable this behavior
when it's created or later on in your applications lifecycle:
const { createLogger, transports } = require('winston');
// Enable exception handling when you create your logger.
const logger = createLogger({
transports: [
new transports.File({ filename: 'combined.log' })
],
exceptionHandlers: [
new transports.File({ filename: 'exceptions.log' })
]
});
// Or enable it later on by adding a transport or using `.exceptions.handle`
const logger = createLogger({
transports: [
new transports.File({ filename: 'combined.log' })
]
});
// Call exceptions.handle with a transport to handle exceptions
logger.exceptions.handle(
new transports.File({ filename: 'exceptions.log' })
);
如果你想将此功能与默认日志器一起使用,只需使用传输实例调用 .exceptions.handle()
。
¥If you want to use this feature with the default logger, simply call
.exceptions.handle()
with a transport instance.
//
// You can add a separate exception logger by passing it to `.exceptions.handle`
//
winston.exceptions.handle(
new winston.transports.File({ filename: 'path/to/exceptions.log' })
);
//
// Alternatively you can set `handleExceptions` to true when adding transports
// to winston.
//
winston.add(new winston.transports.File({
filename: 'path/to/combined.log',
handleExceptions: true
}));
退出或不退出
¥To Exit or Not to Exit
默认情况下,winston 将在记录 uncaughtException 后退出。如果这不是你想要的行为,请设置 exitOnError = false
¥By default, winston will exit after logging an uncaughtException. If this is
not the behavior you want, set exitOnError = false
const logger = winston.createLogger({ exitOnError: false });
//
// or, like this:
//
logger.exitOnError = false;
使用自定义日志器实例时,你可以将单独的传输传递给 exceptionHandlers
属性或在任何传输上设置 handleExceptions
。
¥When working with custom logger instances, you can pass in separate transports
to the exceptionHandlers
property or set handleExceptions
on any
transport.
示例 1
¥Example 1
const logger = winston.createLogger({
transports: [
new winston.transports.File({ filename: 'path/to/combined.log' })
],
exceptionHandlers: [
new winston.transports.File({ filename: 'path/to/exceptions.log' })
]
});
示例 2
¥Example 2
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
handleExceptions: true
})
],
exitOnError: false
});
exitOnError
选项也可以是防止仅在某些类型的错误上退出的函数:
¥The exitOnError
option can also be a function to prevent exit on only
certain types of errors:
function ignoreEpipe(err) {
return err.code !== 'EPIPE';
}
const logger = winston.createLogger({ exitOnError: ignoreEpipe });
//
// or, like this:
//
logger.exitOnError = ignoreEpipe;
拒绝
¥Rejections
使用 winston 处理未捕获的 Promise 拒绝
¥Handling Uncaught Promise Rejections with winston
使用 winston
,可以从你的进程中捕获和记录 unhandledRejection
事件。使用你自己的日志器实例,你可以在创建时或在应用生命周期的稍后启用此行为:
¥With winston
, it is possible to catch and log unhandledRejection
events
from your process. With your own logger instance you can enable this behavior
when it's created or later on in your applications lifecycle:
const { createLogger, transports } = require('winston');
// Enable rejection handling when you create your logger.
const logger = createLogger({
transports: [
new transports.File({ filename: 'combined.log' })
],
rejectionHandlers: [
new transports.File({ filename: 'rejections.log' })
]
});
// Or enable it later on by adding a transport or using `.rejections.handle`
const logger = createLogger({
transports: [
new transports.File({ filename: 'combined.log' })
]
});
// Call rejections.handle with a transport to handle rejections
logger.rejections.handle(
new transports.File({ filename: 'rejections.log' })
);
如果你想将此功能与默认日志器一起使用,只需使用传输实例调用 .rejections.handle()
。
¥If you want to use this feature with the default logger, simply call
.rejections.handle()
with a transport instance.
//
// You can add a separate rejection logger by passing it to `.rejections.handle`
//
winston.rejections.handle(
new winston.transports.File({ filename: 'path/to/rejections.log' })
);
//
// Alternatively you can set `handleRejections` to true when adding transports
// to winston.
//
winston.add(new winston.transports.File({
filename: 'path/to/combined.log',
handleRejections: true
}));
分析
¥Profiling
除了记录消息和元数据之外,winston
还为任何日志器实现了一个简单的分析机制:
¥In addition to logging messages and metadata, winston
also has a simple
profiling mechanism implemented for any logger:
//
// Start profile of 'test'
//
logger.profile('test');
setTimeout(function () {
//
// Stop profile of 'test'. Logging will now take place:
// '17 Jan 21:00:00 - info: test duration=1000ms'
//
logger.profile('test');
}, 1000);
你还可以启动一个计时器并保留一个可以调用 .done()
的引用:
¥Also you can start a timer and keep a reference that you can call .done()
on:
// Returns an object corresponding to a specific timing. When done
// is called the timer will finish and log the duration. e.g.:
//
const profiler = logger.startTimer();
setTimeout(function () {
profiler.done({ message: 'Logging message' });
}, 1000);
所有配置文件消息默认设置为 'info' 级别,消息和元数据都是可选的。对于单个配置文件消息,你可以通过提供具有 level
属性的元数据对象来覆盖默认日志级别:
¥All profile messages are set to 'info' level by default, and both message and
metadata are optional. For individual profile messages, you can override the default log level by supplying a metadata object with a level
property:
logger.profile('test', { level: 'debug' });
查询日志
¥Querying Logs
winston
支持使用类似 Loggly 的选项查询日志。查看 Loggly Search API。具体来说:File
、Couchdb
、Redis
、Loggly
、Nssocket
和 Http
。
¥winston
supports querying of logs with Loggly-like options. See Loggly
Search API. Specifically:
File
, Couchdb
, Redis
, Loggly
, Nssocket
, and Http
.
const options = {
from: new Date() - (24 * 60 * 60 * 1000),
until: new Date(),
limit: 10,
start: 0,
order: 'desc',
fields: ['message']
};
//
// Find items logged between today and yesterday.
//
logger.query(options, function (err, results) {
if (err) {
/* TODO: handle me */
throw err;
}
console.log(results);
});
流日志
¥Streaming Logs
流式传输允许你从所选传输方式流回日志。
¥Streaming allows you to stream your logs back from your chosen transport.
//
// Start at the end.
//
winston.stream({ start: -1 }).on('log', function(log) {
console.log(log);
});
进一步阅读
¥Further Reading
使用默认日志器
¥Using the Default Logger
默认日志器可直接通过 winston
模块访问。你可以在日志器实例上调用的任何方法都可以在默认日志器上使用:
¥The default logger is accessible through the winston
module directly. Any
method that you could call on an instance of a logger is available on the
default logger:
const winston = require('winston');
winston.log('info', 'Hello distributed log files!');
winston.info('Hello again distributed logs');
winston.level = 'debug';
winston.log('debug', 'Now my debug messages are written to console!');
默认情况下,默认日志器上未设置任何传输。你必须通过 add()
和 remove()
方法添加或删除传输:
¥By default, no transports are set on the default logger. You must
add or remove transports via the add()
and remove()
methods:
const files = new winston.transports.File({ filename: 'combined.log' });
const console = new winston.transports.Console();
winston.add(console);
winston.add(files);
winston.remove(console);
或者通过一次调用 configure() 来执行此操作:
¥Or do it with one call to configure():
winston.configure({
transports: [
new winston.transports.File({ filename: 'somefile.log' })
]
});
有关使用 winston
支持的每个单独传输的更多文档,请参阅 winston
传输 文档。
¥For more documentation about working with each individual transport supported
by winston
see the winston
Transports document.
等待在 winston
中写入日志
¥Awaiting logs to be written in winston
在退出进程之前等待日志写入通常很有用。每个 winston.Logger
实例也是一个 [Node.js 流]。当流结束后,所有日志都已刷新到所有传输时,将引发 finish
事件。
¥Often it is useful to wait for your logs to be written before exiting the
process. Each instance of winston.Logger
is also a [Node.js stream]. A
finish
event will be raised when all logs have flushed to all transports
after the stream has been ended.
const transport = new winston.transports.Console();
const logger = winston.createLogger({
transports: [transport]
});
logger.on('finish', function (info) {
// All `info` log messages has now been logged
});
logger.info('CHILL WINSTON!', { seriously: true });
logger.end();
还值得一提的是,如果日志器本身发生错误,日志器也会发出 'error' 事件,如果你不想要未处理的异常,则应该处理或抑制该错误:
¥It is also worth mentioning that the logger also emits an 'error' event if an error occurs within the logger itself which you should handle or suppress if you don't want unhandled exceptions:
//
// Handle errors originating in the logger itself
//
logger.on('error', function (err) { /* Do Something */ });
在 winston 中使用多个日志器
¥Working with multiple Loggers in winston
通常在更大、更复杂的应用中,需要具有不同设置的多个日志器实例。每个日志器负责不同的功能区域(或类别)。这在 winston
中以两种方式公开:通过 winston.loggers
和 winston.Container
的实例。事实上,winston.loggers
只是 winston.Container
的一个预定义实例:
¥Often in larger, more complex, applications it is necessary to have multiple
logger instances with different settings. Each logger is responsible for a
different feature area (or category). This is exposed in winston
in two
ways: through winston.loggers
and instances of winston.Container
. In fact,
winston.loggers
is just a predefined instance of winston.Container
:
const winston = require('winston');
const { format } = winston;
const { combine, label, json } = format;
//
// Configure the logger for `category1`
//
winston.loggers.add('category1', {
format: combine(
label({ label: 'category one' }),
json()
),
transports: [
new winston.transports.Console({ level: 'silly' }),
new winston.transports.File({ filename: 'somefile.log' })
]
});
//
// Configure the logger for `category2`
//
winston.loggers.add('category2', {
format: combine(
label({ label: 'category two' }),
json()
),
transports: [
new winston.transports.Http({ host: 'localhost', port:8080 })
]
});
现在你的日志器已设置好,你可以在应用中的任何文件中要求 winston 并访问这些预配置的日志器:
¥Now that your loggers are setup, you can require winston in any file in your application and access these pre-configured loggers:
const winston = require('winston');
//
// Grab your preconfigured loggers
//
const category1 = winston.loggers.get('category1');
const category2 = winston.loggers.get('category2');
category1.info('logging to file and console transports');
category2.info('logging to http transport');
如果你更喜欢自己管理 Container
,你可以简单地实例化一个:
¥If you prefer to manage the Container
yourself, you can simply instantiate one:
const winston = require('winston');
const { format } = winston;
const { combine, label, json } = format;
const container = new winston.Container();
container.add('category1', {
format: combine(
label({ label: 'category one' }),
json()
),
transports: [
new winston.transports.Console({ level: 'silly' }),
new winston.transports.File({ filename: 'somefile.log' })
]
});
const category1 = container.get('category1');
category1.info('logging to file and console transports');
将控制台传输消息路由到控制台而不是 stdout 和 stderr
¥Routing Console transport messages to the console instead of stdout and stderr
默认情况下,winston.transports.Console
传输将消息发送到 stdout
和 stderr
。在大多数情况下这都可以;但是,在某些情况下这并不可取,包括:
¥By default the winston.transports.Console
transport sends messages to stdout
and stderr
. This
is fine in most situations; however, there are some cases where this isn't desirable, including:
-
使用 VSCode 进行调试并附加到 Node.js 进程(而不是启动该进程)
¥Debugging using VSCode and attaching to, rather than launching, a Node.js process
-
在 AWS Lambda 中编写 JSON 格式的消息
¥Writing JSON format messages in AWS Lambda
-
使用
--silent
选项在 Jest 测试期间记录¥Logging during Jest tests with the
--silent
option
要使传输日志改用 console.log()
、console.warn()
和 console.error()
,请将 forceConsole
选项设置为 true
:
¥To make the transport log use console.log()
, console.warn()
and console.error()
instead, set the forceConsole
option to true
:
const logger = winston.createLogger({
level: 'info',
transports: [new winston.transports.Console({ forceConsole: true })]
});
安装
¥Installation
npm install winston
yarn add winston
运行测试
¥Run Tests
所有 winston 测试都是用 mocha
、nyc
和 assume
编写的。它们可以与 npm
一起运行。
¥All of the winston tests are written with mocha
, nyc
, and
assume
. They can be run with npm
.
npm test
作者:[Charlie Robbins]
¥Author: Charlie Robbins
贡献者:[Jarrett Cruger]、[David Hyde]、[Chris 奥尔德森]
¥Contributors: Jarrett Cruger, David Hyde, Chris Alderson