日志默認(rèn)關(guān)閉,你可以在創(chuàng)建 Fastify 實例時傳入 { logger: true } 或者 { logger: { level: 'info' } } 選項來開啟它。要注意的是,日志無法在運(yùn)行時啟用。為此,我們使用了 abstract-logging。
Fastify 專注于性能,因此使用了 pino 作為日志工具。默認(rèn)的日志級別為 'info'。
開啟日志相當(dāng)簡單:
const fastify = require('fastify')({
logger: true
})
fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})
如果你想為日志配置選項,直接將選項傳遞給 Fastify 實例就可以了。 你可以在 Pino 的文檔中找到全部選項。如果你想指定文件地址,可以:
const fastify = require('fastify')({
logger: {
level: 'info',
file: '/path/to/file' // 將調(diào)用 pino.destination()
}
})
fastify.get('/', options, function (request, reply) {
request.log.info('Some info about the current request')
reply.send({ hello: 'world' })
})
如果需要向 Pino 傳送自定義流 (stream),僅需在 logger 對象中添加 stream 一項即可。
const split = require('split2')
const stream = split(JSON.parse)
const fastify = require('fastify')({
logger: {
level: 'info',
stream: stream
}
})
默認(rèn)情況下,F(xiàn)astify 給每個請求分配了一個 id 以便跟蹤。如果頭部存在 "request-id" 即使用該值,否則會生成一個新的增量 id。你可以通過 Fastify 工廠函數(shù)的 requestIdHeader 與 genReqId 來進(jìn)行自定義。
默認(rèn)的日志工具使用標(biāo)準(zhǔn)的序列化工具,生成包括 req、res 與 err 屬性在內(nèi)的序列化對象??梢越栌芍付ㄗ远x的序列化工具來改變這一行為。
const fastify = require('fastify')({
logger: {
serializers: {
req: function (req) {
return { url: req.url }
}
}
}
})
響應(yīng)的 payload 與 header 可以按如下方式記錄日志 (即便這是不推薦的做法):
const fastify = require('fastify')({
logger: {
prettyPrint: true,
serializers: {
res(res) {
// 默認(rèn)
return {
statusCode: res.statusCode
}
},
req(req) {
return {
method: req.method,
url: req.url,
path: req.path,
parameters: req.parameters,
// 記錄 header 可能會觸犯隱私法律,例如 GDPR (譯注:General Data Protection Regulation)。你應(yīng)該用 "redact" 選項來移除敏感的字段。此外,驗證數(shù)據(jù)也可能在日志中泄露。
headers: req.headers
};
}
}
}
});
注:在 req 方法中,body 無法被序列化。因為請求是在創(chuàng)建子日志時就序列化了,而此時 body 尚未被解析。
以下是記錄 req.body 的一個方法
app.addHook('preHandler', function (req, reply, done) {
if (req.body) {
req.log.info({ body: req.body }, 'parsed body')
}
done()
})
Pino 之外的日志工具會忽略該選項。
你還可以提供自定義的日志實例。直接將實例傳入,取代配置選項就能實現(xiàn)該功能。提供的示例必須實現(xiàn) Pino 的接口,換句話說,便是擁有下列方法: info、error、debug、fatal、warn、trace、child。
示例:
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' })
})
當(dāng)前請求的日志實例在生命周期的各部分均可使用。
Pino 支持低開銷的日志修訂,以隱藏特定內(nèi)容。 舉例來說,出于安全方面的考慮,我們也許想在 HTTP header 的日志中隱藏 Authorization 這一個 header:
const fastify = Fastify({
logger: {
stream: stream,
redact: ['req.headers.authorization'],
level: 'info',
serializers: {
req (req) {
return {
method: req.method,
url: req.url,
headers: req.headers,
hostname: req.hostname,
remoteAddress: req.ip,
remotePort: req.connection.remotePort
}
}
}
}
})
更多信息請看 https://getpino.io/#/docs/redaction。
更多建議: