hapi-pino

repository·master·Indexed 41 days ago

https://github.com/hapijs/hapi-pino

A Hapi plugin for the Pino logger that enables high-performance, JSON-based logging. It decorates the Hapi server with `server.logger` and each request with `request.logger`, while also intercepting standard Hapi `request.log()` and `server.log()` calls. Version 13.0.0 supports Hapi v21 and Pino v9.

Tokens
4.1K
Snippets
5
Records
15
Agent score
48%

What's inside hapi-pino

  1. How hapi-pino decorates Hapi server and requests

    master

    The hapi-pino plugin integrates Pino logging into Hapi by adding logger instances to both the server and individual requests. This allows for both global application logging and request-scoped tracing.

    • Server Decoration: The Hapi server is decorated with server.logger, which is a standard Pino instance. Use this for general application-level logging.
    • Request Decoration: Each Hapi request is decorated with request.logger. This is a Pino child logger bound to the specific request, enabling you to trace all logs associated with a single request lifecycle.
  2. Filter or ignore specific logs

    master

    Use these options to prevent specific routes or tags from being logged:

    • ignorePaths: (string[]) Array of route paths to disable logging (e.g., ['/health']).
    • ignoreTags: (string[]) Array of Hapi route tags to disable logging.
    • ignoreFunc: (function) A function (options, request) => boolean. If it returns true, logging is disabled. This is a more advanced version of ignorePaths and ignoreTags.
    • ignoredEventTags: (object[]) Array of object tags to disable logging for specific Hapi events. Default: { log: '*', request: '*' }.

    Example: Ignoring static content via ignoreFunc

    ignoreFunc: (options, request) => request.path.startsWith('/static')

    Example: Ignoring specific DEBUG and TEST tags

    ignoredEventTags: { log: ['DEBUG', 'TEST'], request: ['DEBUG', 'TEST'] }
  3. Customize Pino serializers and redaction

    master

    You can overwrite default serializers or redact sensitive information using Pino's standard configuration patterns within hapi-pino:

    • serializers: An object to overwrite default serializers (e.g., req, res, err).
    • wrapSerializers: (boolean) If false, custom serializers receive the raw value directly instead of the pre-serialized value. Use this if you want to work with the raw Hapi Request object.
    • redact: (string[] | pino.redactOptions) Paths to be redacted in the log lines (e.g., ['req.headers.authorization']).

    Example: Redacting authorization headers

    {
      serializers: {
        req: require('pino-noir')(['req.headers.authorization']).req
      }
    }

    Example: Using raw request in a custom serializer

    {
      wrapSerializers: false,
      serializers: {
        req (req) {
          // `req` is the raw hapi's `Request` object
          return { message: req.foo };
        }
      }
    }
  4. Control request start and completion logging

    master

    Manage when and how request start and request complete events are logged:

    • logRequestStart: (boolean | (Request) => boolean) Whether to log at the beginning of a request. Passing a function allows conditional logging.
    • logRequestComplete: (boolean | (Request) => boolean) Whether to log at the completion of a request.
    • customRequestStartMessage: (function) Sets the msg property for start logs. Default: (request) => { return 'request start' }.
    • customRequestCompleteMessage: (function) Sets the msg property for completion logs. Default: (request, responseTime) => { return [response] ${request.method} ${request.path} ${request.raw.res.statusCode} (${responseTime}ms)].
    • customRequestErrorMessage: (function) Sets the msg property for failed requests. Default: (request, err) => { return err.message }.
    • customRequestStartLevel: (pino.Level) Log level for start events. Default: 'info'.
    • customRequestCompleteLevel: (pino.Level) Log level for completion events. Default: 'info'.
    • customRequestErrorLevel: (pino.Level) Log level for error events. Default: 'error'.
  5. Configure Hapi log data merging

    master

    Control how data from Hapi's logging interface (server.log or request.log) is structured in Pino:

    • mergeHapiLogData: (boolean) When true, Hapi log data is merged into Pino's logged attributes at the root level. When false (default), data is nested under a data key.

    Example: Merging data

    // server.log(['info'], {hello: 'world'})
    
    // with mergeHapiLogData: true
    // Output: { level: 30, hello: 'world', ... }
    
    // with mergeHapiLogData: false (Default)
    // Output: { level: 30, data: { hello: 'world' } }
  6. Configure child logger bindings

    master

    The getChildBindings option allows you to customize what data is attached to the request-scoped child logger.

    • getChildBindings: (function) A function (request) => { [key]: any } that returns an object to be passed into pinoLogger.child().

    Note: The default is () => ({ req: Request }). If you omit the req field in your custom function, it will be omitted from the request completed log event, but it will still be present in the request start log.

  7. Configure request logging details via options

    master

    You can control which parts of an HTTP request are included in the response event logs using the following boolean options:

    • logPayload: If true, adds the request payload as payload to the log.
    • logQueryParams: If true, adds the request query as queryParams to the log.
    • logPathParams: If true, adds the request params as pathParams to the log.
    • logRouteTags: If true, adds the request route tags (from route.options.tags) as tags to the log.
    • log4xxResponseErrors: If true, responses with status codes in the 400-500 range will have the value returned by the Hapi lifecycle method added to the log as err.
  8. Register the hapi-pino plugin

    master

    To enable Pino logging in your Hapi server, register the hapi-pino plugin. This decorates your server object with a logger method and attaches a child logger to every request object.

    By default, the plugin logs server start/stop events and request lifecycle events (start, complete, and error).

    const Hapi = require('@hapi/hapi');
    const HapiPino = require('hapi-pino');
    
    const init = async () => {
      const server = Hapi.server({
        port: 3000,
        host: 'localhost'
      });
    
      await server.register({
        plugin: HapiPino,
        options: {
          // configuration options go here
        }
      });
    
      await server.start();
    };
    
    init();
  9. Use hapi-pino in a Hapi server

    master

    To use hapi-pino, register it as a plugin in your Hapi server configuration. Once registered, you can access the logger in three ways:

    1. Via request.logger: The fastest way to log within a request handler.
    2. Via server.logger: A decorated API on the server instance for general logging.
    3. Via Hapi's standard logging: Using request.log() or server.log(), which hapi-pino will intercept and process into JSON.

    You can also pass Pino-specific options (like redact) during registration.

    'use strict'
    
    const Hapi = require('@hapi/hapi')
    
    async function start () {
      // Create a server with a host and port
      const server = Hapi.server({
        host: 'localhost',
        port: 3000,
        debug: false, // disable Hapi debug console logging
      })
    
      // Add the route
      server.route({
        method: 'GET',
        path: '/',
        handler: async function (request, h) {
          // request.log is HAPI standard way of logging
          request.log(['a', 'b'], 'Request into hello world')
    
          // you can also use a pino instance, which will be faster
          request.logger.info('In handler %s', request.path)
    
          return 'hello world'
        }
      })
    
      await server.register({
        plugin: require('hapi-pino'),
        options: {
          // Redact Authorization headers, see https://getpino.io/#/docs/redaction
          redact: ['req.headers.authorization']
        }
      })
    
      // also as a decorated API
      server.logger.info('another way for accessing it')
    
      // and through Hapi standard logging system
      server.log(['subsystem'], 'third way for accessing it')
    
      await server.start()
    
      return server
    }
    
    start().catch((err) => {
      console.log(err)
      process.exit(1)
    })
  10. Configure hapi-pino logging options

    master

    The options object passed during plugin registration controls how Pino behaves and what data is included in logs.

    Request Lifecycle Logging

    • logRequestStart: boolean or (Request) => boolean. Determines if a log is emitted when a request starts. Defaults to false (unless configured otherwise).
    • logRequestComplete: boolean or (Request) => boolean. Determines if a log is emitted when a request completes. Defaults to true.
    • logEvents: string[]. A list of Hapi events to log. Defaults to ['onPostStart', 'onPostStop', 'response', 'request-error'].

    Data Inclusion

    • logPayload: boolean. If true, includes the request payload in the response log.
    • logQueryParams: boolean. If true, includes query parameters in the response log.
    • logPathParams: boolean. If true, includes path parameters in the response log.
    • logRouteTags: boolean. If true, includes the route's tags in the response log.
    • log4xxResponseErrors: boolean. If true, includes the error source in the response log for 4xx status codes.

    Customization

    • getChildBindings: (Request) => object. Customizes the object merged into the request's child logger. Defaults to (request) => ({ req: request }).
    • customRequestStartMessage: (Request) => string. Custom message for request start logs.
    • customRequestCompleteMessage: (Request, number) => string. Custom message for request completion logs (receives request and responseTime).
    • customRequestErrorMessage: (Request, Error) => string. Custom message for request error logs.
    • mergeHapiLogData: boolean. If true, merges Hapi event data directly into the log object. If false, wraps it in a data key.
    • messageKey: string. The key used for the message when mergeHapiLogData is true. Defaults to 'msg'.

    Filtering and Ignoring

    • ignorePaths: string[]. A list of paths that should not be logged.
    • ignoreTags: string[]. A list of route tags that should not be logged.
    • ignoreFunc: (options, Request) => boolean. A custom function to determine if a request should be ignored.
    • ignoredEventTags: object. An object mapping event types (log or request) to an array of tags to ignore. Example: { request: ['healthcheck'] }.
  11. Configure Pino serializers and instances

    master

    You can provide your own Pino instance or customize how data is serialized.

    • instance: A pre-existing Pino instance. If provided, hapi-pino will use it instead of creating a new one.
    • stream: The destination stream for logs (e.g., process.stdout).
    • serializers: An object containing custom serializers.
      • req: Serializer for the request object.
      • res: Serializer for the response object.
      • err: Serializer for errors.
    • wrapSerializers: boolean. If true (default), hapi-pino wraps the provided req and res serializers using Pino's standard wrapRequestSerializer and wrapResponseSerializer. Set to false to use them raw.