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.
							 |