日志
日志
¥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
Replyobject passed to theresserializer cannot be fully constructed. When writing a customresserializer, check for the existence of any properties onreplyaside fromstatusCode, which is always present. For example, verify the existence ofgetHeadersbefore 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
reqmethod 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.