Skip to main content

日志

日志

¥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

默认日志器对具有 reqreserr 属性的对象使用标准序列化器。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 the res serializer cannot be fully constructed. When writing a custom res serializer, check for the existence of any properties on reply aside from statusCode, which is always present. For example, verify the existence of getHeaders 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 接口,方法如下:infoerrordebugfatalwarntracesilentchild 和字符串属性 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.