日志
日志
¥Logging
启用日志记录
¥Enable Logging
默认情况下禁用日志记录。在创建 Fastify 实例时通过传递 { logger: true }
或 { logger: { level: 'info' } }
来启用它。请注意,如果日志器被禁用,则无法在运行时启用它。abstract-logging 用于此目的。
¥Logging is disabled by default. Enable it by passing { logger: true }
or
{ logger: { level: 'info' } }
when creating a Fastify instance. Note that if
the logger is disabled, it cannot be enabled at runtime.
abstract-logging is used for
this purpose.
由于 Fastify 专注于性能,它使用 pino 作为其日志器,启用时默认日志级别设置为 'info'
。
¥As Fastify is focused on performance, it uses
pino as its logger, with the default log
level set to 'info'
when enabled.
基本日志设置
¥Basic logging setup
启用生产 JSON 日志器:
¥Enabling the production JSON logger:
const fastify = require('fastify')({
logger: true
})
特定于环境的配置
¥Environment-Specific Configuration
为本地开发、生产和测试环境启用具有适当配置的日志器需要更多配置:
¥Enabling the logger with appropriate configuration for local development, production, and test environments requires more configuration:
const envToLogger = {
development: {
transport: {
target: 'pino-pretty',
options: {
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
},
},
},
production: true,
test: false,
}
const fastify = require('fastify')({
logger: envToLogger[environment] ?? true // defaults to true if no entry matches in the map
})
⚠️ pino-pretty
需要作为开发依赖安装。出于性能原因,默认情况下不包含它。
¥⚠️ pino-pretty
needs to be installed as a dev dependency. It is not included
by default for performance reasons.
用法
¥Usage
日志器可以在路由处理程序中使用,如下所示:
¥The logger can be used in route handlers as follows:
fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})
使用 Fastify 实例中的 Pino 实例在路由处理程序外部触发新日志:
¥Trigger new logs outside route handlers using the Pino instance from the Fastify instance:
fastify.log.info('Something important happened!');
传递日志器选项
¥Passing Logger Options
要将选项传递给日志器,请将它们提供给 Fastify。有关可用选项,请参阅 Pino 文档。要指定文件目标,请使用:
¥To pass options to the logger, provide them to Fastify. See the Pino documentation for available options. To specify a file destination, use:
const fastify = require('fastify')({
logger: {
level: 'info',
file: '/path/to/file' // Will use pino.destination()
}
})
fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})
要将自定义流传递给 Pino 实例,请将 stream
字段添加到日志器对象:
¥To pass a custom stream to the Pino instance, add a stream
field to the logger
object:
const split = require('split2')
const stream = split(JSON.parse)
const fastify = require('fastify')({
logger: {
level: 'info',
stream: stream
}
})
高级日志器配置
¥Advanced Logger Configuration
请求 ID 跟踪
¥Request ID Tracking
默认情况下,Fastify 会为每个请求添加一个 ID,以便于跟踪。如果设置了 requestIdHeader
选项并且存在相应的标头,则使用其值;否则,生成一个新的增量 ID。请参阅 Fastify Factory requestIdHeader
和 Fastify Factory genReqId
了解自定义选项。
¥By default, Fastify adds an ID to every request for easier tracking. If the
requestIdHeader
option is set and the corresponding header is present, its
value is used; otherwise, a new incremental ID is generated. See Fastify Factory
requestIdHeader
and Fastify Factory
genReqId
for customization options.
Serializers
默认日志器对具有 req
、res
和 err
属性的对象使用标准序列化器。req
对象是 Fastify Request
对象,res
对象是 Fastify Reply
对象。此行为可以使用自定义序列化器进行定制。
¥The default logger uses standard serializers for objects with req
, res
, and
err
properties. The req
object is the Fastify Request
object, and the res
object is the Fastify Reply
object. This
behavior can be customized with custom serializers.
const fastify = require('fastify')({
logger: {
serializers: {
req (request) {
return { url: request.url }
}
}
}
})
例如,可以使用以下方法记录响应有效负载和标头(不推荐):
¥For example, the response payload and headers could be logged using the approach below (not recommended):
const fastify = require('fastify')({
logger: {
transport: {
target: 'pino-pretty'
},
serializers: {
res (reply) {
// The default
return {
statusCode: reply.statusCode
}
},
req (request) {
return {
method: request.method,
url: request.url,
path: request.routeOptions.url,
parameters: request.params,
// Including headers in the log could violate privacy laws,
// e.g., GDPR. Use the "redact" option to remove sensitive
// fields. It could also leak authentication data in the logs.
headers: request.headers
};
}
}
}
});
🛈 注意:在某些情况下,传递给
res
序列化器的Reply
对象无法完全构造。编写自定义res
序列化器时,请检查除statusCode
之外的reply
上是否存在任何属性,statusCode
始终存在。例如,在调用getHeaders
之前验证它的存在:¥🛈 Note: In some cases, the
Reply
object passed to theres
serializer cannot be fully constructed. When writing a customres
serializer, check for the existence of any properties onreply
aside fromstatusCode
, which is always present. For example, verify the existence ofgetHeaders
before calling it:
const fastify = require('fastify')({
logger: {
transport: {
target: 'pino-pretty'
},
serializers: {
res (reply) {
// The default
return {
statusCode: reply.statusCode,
headers: typeof reply.getHeaders === 'function'
? reply.getHeaders()
: {}
}
},
}
}
});
🛈 注意:主体无法在
req
方法内序列化,因为请求是在创建子日志器时序列化的。那时,本体还没有被解析。¥🛈 Note: The body cannot be serialized inside a
req
method because the request is serialized when the child logger is created. At that time, the body is not yet parsed.
请参阅以下记录 req.body
的方法:
¥See the following approach to log req.body
:
app.addHook('preHandler', function (req, reply, done) {
if (req.body) {
req.log.info({ body: req.body }, 'parsed body')
}
done()
})
🛈 注意:确保序列化器永远不会抛出错误,因为这可能导致 Node 进程退出。有关更多信息,请参阅 Pino 文档。
¥🛈 Note: Ensure serializers never throw errors, as this can cause the Node process to exit. See the Pino documentation for more information.
Pino 以外的任何日志器都会忽略此选项。
¥Any logger other than Pino will ignore this option.
使用自定义日志器
¥Using Custom Loggers
可以通过将自定义日志器实例作为 loggerInstance
传递来提供它。日志器必须符合 Pino 接口,方法如下:info
、error
、debug
、fatal
、warn
、trace
、silent
、child
和字符串属性 level
。
¥A custom logger instance can be supplied by passing it as loggerInstance
. The
logger must conform to the Pino interface, with methods: info
, error
,
debug
, fatal
, warn
, trace
, silent
, child
, and a string property
level
.
示例:
¥Example:
const log = require('pino')({ level: 'info' })
const fastify = require('fastify')({ loggerInstance: log })
log.info('does not have request information')
fastify.get('/', function (request, reply) {
request.log.info('includes request information, but is the same logger instance as `log`')
reply.send({ hello: 'world' })
})
当前请求的日志器实例在 lifecycle 的每个部分都可用。
¥The logger instance for the current request is available in every part of the lifecycle.
日志编辑
¥Log Redaction
Pino 支持低开销日志编辑,用于隐藏记录日志中特定属性的值。例如,记录除 Authorization
标头之外的所有 HTTP 标头以确保安全:
¥Pino supports low-overhead log redaction for obscuring
values of specific properties in recorded logs. For example, log all HTTP
headers except the Authorization
header for security:
const fastify = Fastify({
logger: {
stream: stream,
redact: ['req.headers.authorization'],
level: 'info',
serializers: {
req (request) {
return {
method: request.method,
url: request.url,
headers: request.headers,
host: request.host,
remoteAddress: request.ip,
remotePort: request.socket.remotePort
}
}
}
}
})
请参阅 https://pino.nodejs.cn/#/docs/redaction 了解更多详情。
¥See https://pino.nodejs.cn/#/docs/redaction for more details.