ロギング
ロギング
ロギングを有効にする
ロギングはデフォルトで無効になっており、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インスタンスに渡したい場合は、loggerオブジェクトにstreamフィールドを追加するだけです。
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
を参照してください。
デフォルトのロガーは、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
シリアライザーを記述する場合は、常に存在するstatusCode
以外のreply
のプロパティの存在を確認する必要があります。たとえば、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インターフェースに準拠する必要があります。つまり、次のメソッドを持っている必要があります: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は、記録されたログ内の特定のプロパティの値を不明瞭にするための、オーバーヘッドの少ないログリダクションをサポートしています。例として、セキュリティ上の懸念から、Authorization
ヘッダーを除くすべてのHTTPヘッダーをログに記録したい場合があります
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を参照してください。