{"id":13465044,"url":"https://github.com/hapijs/hapi-pino","last_synced_at":"2025-03-25T13:32:58.876Z","repository":{"id":7405653,"uuid":"56257025","full_name":"hapijs/hapi-pino","owner":"hapijs","description":"🌲 Hapi plugin for the Pino logger","archived":false,"fork":false,"pushed_at":"2023-08-08T12:19:49.000Z","size":249,"stargazers_count":148,"open_issues_count":12,"forks_count":60,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-05-23T00:19:54.645Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hapijs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-04-14T17:29:11.000Z","updated_at":"2024-03-01T19:41:50.000Z","dependencies_parsed_at":"2023-11-06T19:25:01.140Z","dependency_job_id":"eed1f472-f164-4d3f-bf8b-745ccf4b9de9","html_url":"https://github.com/hapijs/hapi-pino","commit_stats":null,"previous_names":["pinojs/hapi-pino"],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapijs%2Fhapi-pino","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapijs%2Fhapi-pino/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapijs%2Fhapi-pino/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hapijs%2Fhapi-pino/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hapijs","download_url":"https://codeload.github.com/hapijs/hapi-pino/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221361352,"owners_count":16805182,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T14:00:55.906Z","updated_at":"2024-10-29T16:30:29.541Z","avatar_url":"https://github.com/hapijs.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# hapi-pino\u0026nbsp;\u0026nbsp;![Tests Status](https://github.com/pinojs/hapi-pino/actions/workflows/test.yml/badge.svg)\n\n\n[Hapi](http://hapijs.com) plugin for the [Pino](https://github.com/pinojs/pino) logger. It logs in JSON for easy\npost-processing.\n\n## Hapi and Pino versions supported by hapi-pino\n\n| hapi-pino     | hapi          | pino          |\n| ------------- |:--------------|:--------------|\n| v12.x         | v21           | v8            |\n| v11.x         | v20           | v8            |\n| v9.x - v10.x  | v20           | v7            |\n| v8.x          | v18, v19, v20 | v6            |\n| v6.x          | v17, v18, v19 | v5            |\n| v5.x          | v17, v18      | v5            |\n| v3.x - v4.x   | v17           | v4            |\n| v2.x          | v16           | v4            |\n\n## Install\n\n```\nnpm install hapi-pino\n```\n\n## Usage\n\n```js\n'use strict'\n\nconst Hapi = require('@hapi/hapi')\n\nasync function start () {\n  // Create a server with a host and port\n  const server = Hapi.server({\n    host: 'localhost',\n    port: 3000,\n    debug: false, // disable Hapi debug console logging\n  })\n\n  // Add the route\n  server.route({\n    method: 'GET',\n    path: '/',\n    handler: async function (request, h) {\n      // request.log is HAPI standard way of logging\n      request.log(['a', 'b'], 'Request into hello world')\n\n      // you can also use a pino instance, which will be faster\n      request.logger.info('In handler %s', request.path)\n\n      return 'hello world'\n    }\n  })\n\n  await server.register({\n    plugin: require('hapi-pino'),\n    options: {\n      // Redact Authorization headers, see https://getpino.io/#/docs/redaction\n      redact: ['req.headers.authorization']\n    }\n  })\n\n  // also as a decorated API\n  server.logger.info('another way for accessing it')\n\n  // and through Hapi standard logging system\n  server.log(['subsystem'], 'third way for accessing it')\n\n  await server.start()\n\n  return server\n}\n\nstart().catch((err) =\u003e {\n  console.log(err)\n  process.exit(1)\n})\n```\n\n## API\n\n- [Options](#options)\n- [Server decorations](#serverdecorations)\n- [Request decorations](#requestdecorations)\n- [Hapi Events](#hapievents)\n\n**hapi-pino** goal is to enable Hapi applications to log via [pino][pino]. To enable this, it decorates both the [server](#serverdecorations) and the [request](#requestadditions). Moreover, **hapi-pino**\n binds to the Hapi events system as described in the [\"Hapi\nevents\"](#hapievents) section.\n\n### Options\n### `options.logPayload: boolean`\n\n  **Default**: `false`\n\n  When enabled, add the request payload as `payload` to the `response` event log.\n\n### `options.logQueryParams: boolean`\n\n  **Default**: `false`\n\n  When enabled, add the request query as `queryParams` to the `response` event log.\n\n### `options.logPathParams: boolean`\n\n  **Default**: `false`\n\n  When enabled, add the request params as `pathParams` to the `response` event log.\n\n### `options.logRouteTags: boolean`\n\n  **Default**: `false`\n\n  When enabled, add the request route tags (as configured in hapi `route.options.tags`) `tags` to the `response` event log.\n\n### `options.log4xxResponseErrors: boolean`\n\n  **Default**: `false`\n\n  When enabled, responses with status codes in the 400-500 range will have the value returned by the hapi lifecycle method added to the `response` event log as `err`.\n\n### `options.logRequestStart: boolean | (Request) =\u003e boolean`\n\n  **Default**: false\n\n  Whether hapi-pino should add a `log.info()` at the beginning of Hapi requests for the given Request.\n\n  For convenience, you can pass in `true` to always log `request start` events, or `false` to disable logging `request start` events\n\n  Note: when `logRequestStart` is enabled and `getChildBindings` is configured to omit the `req` field, then the `req` field will be\n  omitted from the `request completed` log event but the `req` field will always be there for the start log. This behavior is useful if you want to separate requests from responses and link the\n  two via requestId (frequently done via `headers['x-request-id']`) , where \"request start\" only logs the request and a requestId,\n  and `request completed` only logs the response and the requestId.\n\n### `options.customRequestStartMessage`\n\n  **Default**: `(request) =\u003e { return 'request start' }`\n\n  Set to a function `(request) =\u003e { /* returns message string */ }`. This function will be invoked at each request received, setting the \"msg\" property to the returned string. If not set, default value will be used.\n\n### `options.logRequestComplete: boolean | (Request) =\u003e Boolean`\n\n  **Default**: true\n\n  Whether hapi-pino should add a `log.info()` at the completion of Hapi requests for the given Request.\n\n  For convenience, you can pass in `true` to always log `request complete` events, or `false` to disable logging `request complete` events\n\n### `options.customRequestCompleteMessage`\n\n  **Default**: `` (request, responseTime) =\u003e { return `[response] ${request.method} ${request.path} ${request.raw.res.statusCode} (${responseTime}ms)` } ``\n\n  Set to a function `(request, responseTime) =\u003e { /* returns message string */ }`. This function will be invoked at each completed request, setting the \"msg\" property to the returned string. If not set, default value will be used.\n\n### `options.customRequestErrorMessage`\n\n  **Default**: `(request, err) =\u003e { return err.message }`\n\n  Set to a function `(request, err) =\u003e { /* returns message string */ }`. This function will be invoked at each failed request, setting the \"msg\" property to the returned string. If not set, default value will be used.\n\n### `options.customRequestStartLevel:  pino.Level`\n\n  **Default**: 'info'\n\n  The log level to use for `request start` events.\n\n### `options.customRequestCompleteLevel:  pino.Level`\n\n**Default**: 'info'\n\n  The log level to use for `request complete` events.\n\n### `options.customRequestErrorLevel:  pino.Level`\n\n**Default**: 'error'\n\n  The logging level to use for `request-error` events.\n\n### `options.stream` Pino.DestinationStream\n\n  **Default**: `process.stdout`\n\n  the binary stream to write stuff to\n\n### `options.tags: ({ [key in pino.Level]?: string })`\n\n  **Default**: exposed via `hapi-pino.levelTags`\n\n  A map to specify pairs of Hapi log tags and levels.  The tags `trace`, `debug`, `info`, `warn`, and `error` map to their corresponding level.\n  Any mappings you supply take precedence over the default mappings.\n\n### `options.allTags: pino.Level`\n\n  **Default**: `'info'`\n\n The logging level to apply to all tags not matched by `tags`\n\n### `options.serializers: { [key: string]: pino.SerializerFn }`\n\n An object to overwrite the default serializers. You can but don't have to overwrite all of them.\n\n **Example**:  \n To redact the authorization header in the logs:\n\n  ```js\n  {\n    req: require('pino-noir')(['req.headers.authorization']).req\n    res: ...\n    err: ...\n  }\n  ```\n\n### `options.wrapSerializers: boolean`\n\n  **Default**: `true`\n\n  When `false`, custom serializers will be passed the raw value directly.\n\n  **Example**:\n  If you prefer to work with the raw value directly, or you want to honor the custom serializers already defined by `options.instance`, you can pass in `options.wrapSerializers` as `false`:\n\n  ```js\n  {\n    wrapSerializers: false,\n    serializers: {\n      req (req) {\n        // `req` is the raw hapi's `Request` object, not the already serialized request from `pino.stdSerializers.req`.\n        return {\n          message: req.foo\n        };\n      }\n    }\n  }\n  ```\n\n### `options.instance: Pino`\n\n  Uses a previously created Pino instance as the logger.\n  The instance's `stream` and `serializers` take precedence.\n\n### `options.logEvents: string[] | false | null`\n\n  **Default**: `['onPostStart', 'onPostStop', 'response', 'request-error']` (all events)\n\n  Takes an array of strings with the events to log.\n\n  Set to `false/null` to disable all events. Even though there is no `request-error` [Hapi Event](#hapievents), the options enables the logging of failed requests.\n\n### `options.mergeHapiLogData: boolean`\n\n  **Default**: `false`\n\n  When enabled, Hapi-pino will merge the data received\n  from Hapi's logging interface (`server.log(tags, data)` or `request.log(tags, data)`)\n  into Pino's logged attributes at root level. If data is a string, it will be used as the value for the `msg` key.\n  When disabled, Hapi-pino will keep data under a `data` key.\n\n  **Example**:  \n  ```js\n  server.log(['info'], {hello: 'world'})\n\n  // with mergeHapiLogData: true\n  { level: 30, hello: 'world', ...}\n\n  // with mergeHapiLogData: false (Default)\n  { level: 30, data: { hello: 'world' }}\n  ```\n\n### `options.getChildBindings: (request) =\u003e { [key]: any }`\n\n  **Default**: `() =\u003e { req: Request }`, which automatically adds the request to every pino log call\n\n  Takes a function with the request as an input, and returns the object that will be passed into pinoLogger.child().\n\n  Note: Omitting `req` from the child bindings will omit it from all logs, most notably the response log, except \"request start\".\n\n### `options.ignorePaths: string[]`\n  Takes an array of string routes and disables logging for each.  Useful for health checks or any route that does not need logging.\n\n  **Example**:  \n  Do not log for /health route\n  ```js\n  ignorePaths: ['/health']\n  ```\n\n### `options.ignoreTags: string[]`\n  Takes an array of string tags and disables logging for each.  Useful for health checks or any route that does not need logging.\n\n  **Example**:  \n  Do not log for route with `healthcheck` tag\n  ```js\n  ignoreTags: ['healthcheck']\n  ```\n\n### `options.ignoreFunc: (options, request) =\u003e boolean`\n  Takes a function that receives the plugin options and the request as parameters, and returns a boolean. Logging will be disabled if the return value is `true`. Useful for scenarios where the `ignorePaths` or `ignoreTags` options can't achieve what is intended.\n\n  **Example**:\n  Do not log routes relative to static content\n  ```js\n  ignoreFunc: (options, request) =\u003e request.path.startsWith('/static')\n  ```\n\n  **Note**: if `ignoreFunc` is used, the other two options that can be used to ignore / disable logging (`ignorePaths` and `ignoreTags`) are effectively discarded. So `ignoreFunc` can be seen a more advanced option. For instance, you can easily re-implement the `ignorePaths` functionality as follows:\n\n  ```js\n  ignoreFunc: (options, request) =\u003e myIgnorePaths.include(request.path)\n  ```\n\n  (where `myIgnorePaths` would be an array with paths to be ignored).\n\n\n### `options.ignoredEventTags: object[]`\n  Takes an array of object tags and disables logging for each.  Useful for debug logs or any other tags that does not need logging.\n\n  **Default**: `{ log: '*', request: '*' }`, Logs all the events emitted by server.log and request.log without filtering event tags\n\n  **Example**:\n  Do not log the events for DEBUG and TEST tag\n  ```js\n  ignoredEventTags: { log: ['DEBUG', 'TEST'], request: ['DEBUG', 'TEST'] }\n  server.log(['DEBUG'], 'DEBUG')\n  ```\n\n\n### `options.level: Pino.Level`\n  **Default**: `'info'`\n\n  Set the minimum level that Pino should log out. See [Level](https://github.com/pinojs/pino/blob/master/docs/api.md#level).\n\n  **Example**:  \n  Configure Pino to output all `debug` or higher events:\n  ```js\n  level: 'debug'\n  ```\n\n### `options.redact: string[] | pino.redactOptions`\n\n  Path to be redacted in the log lines. See the [log redaction](https://getpino.io/#/docs/redaction) docs for more details.\n\n\u003ca name=\"serverdecorations\"\u003e\u003c/a\u003e\n### Server Decorations\n\n**hapi-pino** decorates the Hapi server with `server.logger`, which is an instance of\n  [pino][pino]. See its doc for the way to actual log.\n\n\u003ca name=\"requestdecorations\"\u003e\u003c/a\u003e\n### Request Decorations\n\n**hapi-pino** decorates the Hapi request with:\n\n- `request.logger`, which is an instance of [pino][pino] bound to the current request, so you can trace all the logs of a given request. See [pino][pino] doc for the way to actual log.\n\n\u003ca name=\"hapievents\"\u003e\u003c/a\u003e\n### Hapi Events\n\n**hapi-pino** listens to some Hapi events:\n\n- `'onRequest'`, to create a request-specific child logger\n- `'response'`, to log at `'info'` level when a request is completed\n- `'request'`, to support logging via the Hapi `request.log()` method and to log at `'warn'` level when a request errors or when request received contains an invalid `accept-encoding` header, see `tags` and `allTags` options.\n- `'log'`, to support logging via the Hapi `server.log()` method and to log in case of an internal server event, see `tags` and `allTags` options.\n- `'onPostStart'`, to log when the server is started\n- `'onPostStop'`, to log when the server is stopped\n\n## Acknowledgements\n\nThis project was kindly sponsored by [nearForm](http://nearform.com).\n\n## License\n\nMIT\n\n[pino]: https://github.com/pinojs/pino\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhapijs%2Fhapi-pino","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhapijs%2Fhapi-pino","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhapijs%2Fhapi-pino/lists"}