跳至主要内容
版本:最新版本 (v5.0.x)

日志记录

日志记录

启用日志记录

默认情况下日志记录是禁用的,您可以在创建 Fastify 实例时传递 { logger: true }{ logger: { level: 'info' } } 来启用它。请注意,如果日志记录被禁用,则无法在运行时启用它。为此,我们使用 abstract-logging

由于 Fastify 侧重于性能,因此在启用时,它使用 pino 作为其日志记录器,默认日志级别设置为 'info'

启用生产环境 JSON 日志记录器

const fastify = require('fastify')({
logger: true
})

为本地开发和生产以及测试环境启用具有适当配置的日志记录器需要更多配置

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 需要作为开发依赖项安装,默认情况下不包含。

用法

您可以在路由处理程序中像这样使用日志记录器

fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})

您可以通过使用 Fastify 实例中的 Pino 实例触发新的日志,这些日志位于路由处理程序之外

fastify.log.info('Something important happened!');

如果您想向日志记录器传递一些选项,只需将其传递给 Fastify。您可以在 Pino 文档 中找到所有可用的选项。如果您想指定文件目标,请使用

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 实例传递自定义流,只需在日志记录器对象中添加一个流字段。

const split = require('split2')
const stream = split(JSON.parse)

const fastify = require('fastify')({
logger: {
level: 'info',
stream: stream
}
})

默认情况下,Fastify 为每个请求添加一个 ID 以便于跟踪。如果设置了 requestIdHeader 选项并且存在相应的标头,则使用其值,否则生成新的增量 ID。有关自定义选项,请参阅 Fastify 工厂 requestIdHeader 和 Fastify 工厂 genReqId

默认日志记录器配置了一组标准序列化程序,这些序列化程序使用 reqreserr 属性序列化对象。req 收到的对象是 Fastify Request 对象,而 res 收到的对象是 Fastify Reply 对象。可以通过指定自定义序列化程序来自定义此行为。

const fastify = require('fastify')({
logger: {
serializers: {
req (request) {
return { url: request.url }
}
}
}
})

例如,可以使用以下方法记录响应有效负载和标头(即使它**不建议**这样做)

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 序列化程序时,有必要检查 reply 上除了始终存在的 statusCode 之外的任何属性是否存在。例如,必须在调用 getHeaders 之前验证其是否存在

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 方法内序列化主体。那时,主体尚未解析。

请参阅记录 req.body 的方法

app.addHook('preHandler', function (req, reply, done) {
if (req.body) {
req.log.info({ body: req.body }, 'parsed body')
}
done()
})

**注意**:应注意确保序列化程序永远不会抛出异常,因为从序列化程序抛出的异常有可能导致 Node 进程退出。有关更多信息,请参阅有关序列化程序的 Pino 文档

除 Pino 之外的任何其他日志记录器都会忽略此选项。

您也可以提供自己的日志记录器实例。无需传递配置选项,而是传递实例。您提供的日志记录器必须符合 Pino 接口;也就是说,它必须具有以下方法:infoerrordebugfatalwarntracesilentchild 和一个字符串属性 level

示例

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' })
})

当前请求的日志记录器实例在 生命周期 的每个部分都可用。

日志脱敏

Pino 支持低开销的日志脱敏,用于隐藏记录日志中特定属性的值。例如,出于安全考虑,我们可能希望记录所有 HTTP 标头,但 Authorization 标头除外

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://getpino.io/#/docs/redaction