日誌記錄
日誌記錄
啟用日誌記錄
日誌記錄預設為停用,您可以在建立 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 實例,只需將 stream 欄位新增至記錄器物件。
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
。
預設記錄器配置了一組標準序列化器,這些序列化器會序列化具有 req
、res
和 err
屬性的物件。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
方法中序列化 body,因為請求是在建立子記錄器時序列化的。那時,body 尚未解析。
請參閱記錄 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 介面;也就是說,它必須具有以下方法:info
、error
、debug
、fatal
、warn
、trace
、silent
、child
和一個字串屬性 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。