You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
5.9 KiB
216 lines
5.9 KiB
3 years ago
|
<h1 align="center">Fastify</h1>
|
||
|
|
||
|
## Logging
|
||
|
|
||
|
### Enable 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](https://www.npmjs.com/package/abstract-logging) for this
|
||
|
purpose.
|
||
|
|
||
|
As Fastify is focused on performance, it uses
|
||
|
[pino](https://github.com/pinojs/pino) as its logger, with the default log
|
||
|
level, when enabled, set to `'info'`.
|
||
|
|
||
|
Enabling the production JSON logger:
|
||
|
|
||
|
```js
|
||
|
const fastify = require('fastify')({
|
||
|
logger: true
|
||
|
})
|
||
|
```
|
||
|
|
||
|
Enabling the logger with appropriate configuration for both local development
|
||
|
and production environment requires bit more configuration:
|
||
|
```js
|
||
|
const fastify = require('fastify')({
|
||
|
logger: {
|
||
|
prettyPrint:
|
||
|
environment === 'development'
|
||
|
? {
|
||
|
translateTime: 'HH:MM:ss Z',
|
||
|
ignore: 'pid,hostname'
|
||
|
}
|
||
|
: false
|
||
|
}
|
||
|
})
|
||
|
```
|
||
|
⚠️ `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:
|
||
|
|
||
|
```js
|
||
|
fastify.get('/', options, function (request, reply) {
|
||
|
request.log.info('Some info about the current request')
|
||
|
reply.send({ hello: 'world' })
|
||
|
})
|
||
|
```
|
||
|
|
||
|
You can trigger new logs outside route handlers by using the Pino instance from
|
||
|
the Fastify instance:
|
||
|
```js
|
||
|
fastify.log.info('Something important happened!');
|
||
|
```
|
||
|
|
||
|
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](https://github.com/pinojs/pino/blob/master/docs/api.md#pinooptions-stream).
|
||
|
If you want to specify a file destination, use:
|
||
|
|
||
|
```js
|
||
|
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' })
|
||
|
})
|
||
|
```
|
||
|
|
||
|
If you want to pass a custom stream to the Pino instance, just add a stream
|
||
|
field to the logger object.
|
||
|
|
||
|
```js
|
||
|
const split = require('split2')
|
||
|
const stream = split(JSON.parse)
|
||
|
|
||
|
const fastify = require('fastify')({
|
||
|
logger: {
|
||
|
level: 'info',
|
||
|
stream: stream
|
||
|
}
|
||
|
})
|
||
|
```
|
||
|
|
||
|
<a id="logging-request-id"></a>
|
||
|
|
||
|
By default, Fastify adds an ID to every request for easier tracking. If the
|
||
|
"request-id" header is present its value is used, otherwise a new incremental ID
|
||
|
is generated. See Fastify Factory
|
||
|
[`requestIdHeader`](./Server.md#factory-request-id-header) and Fastify Factory
|
||
|
[`genReqId`](./Server.md#genreqid) for customization options.
|
||
|
|
||
|
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`](./Request.md) object, while the object
|
||
|
received by `res` is the Fastify [`Reply`](./Reply.md) object. This behaviour
|
||
|
can be customized by specifying custom serializers.
|
||
|
```js
|
||
|
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*):
|
||
|
|
||
|
```js
|
||
|
const fastify = require('fastify')({
|
||
|
logger: {
|
||
|
prettyPrint: true,
|
||
|
serializers: {
|
||
|
res (reply) {
|
||
|
// The default
|
||
|
return {
|
||
|
statusCode: reply.statusCode
|
||
|
}
|
||
|
},
|
||
|
req (request) {
|
||
|
return {
|
||
|
method: request.method,
|
||
|
url: request.url,
|
||
|
path: request.routerPath,
|
||
|
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
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
```
|
||
|
**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.
|
||
|
|
||
|
See an approach to log `req.body`
|
||
|
|
||
|
```js
|
||
|
app.addHook('preHandler', function (req, reply, done) {
|
||
|
if (req.body) {
|
||
|
req.log.info({ body: req.body }, 'parsed body')
|
||
|
}
|
||
|
done()
|
||
|
})
|
||
|
```
|
||
|
|
||
|
|
||
|
*Any logger other than Pino will ignore this option.*
|
||
|
|
||
|
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`, `child`.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
```js
|
||
|
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' })
|
||
|
})
|
||
|
```
|
||
|
|
||
|
*The logger instance for the current request is available in every part of the
|
||
|
[lifecycle](./Lifecycle.md).*
|
||
|
|
||
|
## Log Redaction
|
||
|
|
||
|
[Pino](https://getpino.io) 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:
|
||
|
|
||
|
```js
|
||
|
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,
|
||
|
hostname: request.hostname,
|
||
|
remoteAddress: request.ip,
|
||
|
remotePort: request.socket.remotePort
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
```
|
||
|
|
||
|
See https://getpino.io/#/docs/redaction for more details.
|