日志
日志
¥Logging
启用日志记录
¥Enable logging
默认情况下,日志记录是禁用的,你可以在创建 Fastify 实例时通过传递 { logger: true }
或 { logger: { level: 'info' } }
来启用它。请注意,如果日志器被禁用,则无法在运行时启用它。我们将 abstract-logging 用于此目的。
¥Logging is disabled by default, and you can enable it by passing { logger: true
}
or { logger: { level: 'info' } }
when you create a Fastify instance. Note
that if the logger is disabled, it is impossible to enable it at runtime. We use
abstract-logging for this
purpose.
由于 Fastify 专注于性能,它使用 pino 作为其日志器,启用时默认日志级别设置为 'info'
。
¥As Fastify is focused on performance, it uses
pino as its logger, with the default log
level, when enabled, set to 'info'
.
启用生产 JSON 日志器:
¥Enabling the production JSON logger:
const fastify = require('fastify')({
logger: true
})
为本地开发、生产和测试环境启用具有适当配置的日志器需要更多配置:
¥Enabling the logger with appropriate configuration for both local development and production and test environment requires a bit 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
你可以在路由处理程序中使用这样的日志器:
¥You can use the logger like this in your route handlers:
fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})
你可以使用 Fastify 实例中的 Pino 实例在路由处理程序外部触发新日志:
¥You can trigger new logs outside route handlers by using the Pino instance from the Fastify instance:
fastify.log.info('Something important happened!');
如果你想将一些选项传递给日志器,只需将它们传递给 Fastify 即可。你可以在 Pino 文档 中找到所有可用选项。如果要指定文件目标,请使用:
¥If you want to pass some options to the logger, just pass them to Fastify. You can find all available options in the Pino documentation. If you want 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 实例,只需向 logger 对象添加一个流字段即可。
¥If you want to pass a custom stream to the Pino instance, just 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
}
})
默认情况下,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 than
its value is used, otherwise a new incremental ID is generated. See Fastify
Factory requestIdHeader
and Fastify
Factory genReqId
for customization options.
默认日志器配置了一组标准序列化器,用于序列化具有 req
、res
和 err
属性的对象。req
收到的对象是 Fastify Request
对象,而 res
收到的对象是 Fastify Reply
对象。可以通过指定自定义序列化器来定制此行为。
¥The default logger is configured with a set of standard serializers that
serialize objects with req
, res
, and err
properties. The object received
by req
is the Fastify Request
object, while the object
received by res
is the Fastify Reply
object. This behavior
can be customized by specifying 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 (even if it is 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 the headers in the log could be in violation
// of privacy laws, e.g. GDPR. You should 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 certain cases, the Reply
object passed to the res
serializer cannot be fully constructed. When writing a custom res
serializer,
it is necessary to check for the existence of any properties on reply
aside
from statusCode
, which is always present. For example, the existence of
getHeaders
must be verified before it can be called:
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 we create the child logger. At that time, the body is
not yet parsed.
查看记录 req.body
的方法
¥See an 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: Care should be taken to ensure serializers never throw, as an error thrown from a serializer has the potential to cause the Node process to exit. See the Pino documentation on serializers for more information.
Pino 以外的任何日志器都会忽略此选项。
¥Any logger other than Pino will ignore this option.
你还可以提供自己的日志器实例。不传递配置选项,而是传递实例。你提供的日志器必须符合 Pino 接口;也就是说,它必须具有以下方法:info
、error
、debug
、fatal
、warn
、trace
、silent
、child
和字符串属性 level
。
¥You can also supply your own logger instance. Instead of passing configuration
options, pass the instance. The logger you supply must conform to the Pino
interface; that is, it must have the following 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')({ logger: 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 支持低开销日志编辑,用于隐藏记录日志中特定属性的值。例如,出于安全考虑,我们可能希望记录所有 HTTP 标头(减去 Authorization
标头):
¥Pino supports low-overhead log redaction for obscuring
values of specific properties in recorded logs. As an example, we might want to
log all the HTTP headers minus the Authorization
header for security concerns:
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.