[
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    open-pull-requests-limit: 10\n\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/workflows/bench.yml",
    "content": "name: Benchmarks\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n        - 'docs/**'\n        - '*.md'\n  pull_request:\n    paths-ignore:\n        - 'docs/**'\n        - '*.md'\n\npermissions:\n  contents: read\n\njobs:\n  benchmark_current:\n    name: benchmark current\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v6.0.2\n        with:\n          ref: ${{ github.base_ref }}\n          persist-credentials: false\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: lts/*\n      - name: Install Modules\n        run: npm i --ignore-scripts\n      - name: Run Benchmark\n        run: npm run bench | tee current.txt\n      - name: Upload Current Results\n        uses: actions/upload-artifact@v4\n        with:\n          name: current\n          path: current.txt\n\n  benchmark_branch:\n    name: benchmark branch\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v6.0.2\n        with:\n          persist-credentials: false\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: lts/*\n      - name: Install Modules\n        run: npm i --ignore-scripts\n      - name: Run Benchmark\n        run: npm run bench | tee branch.txt\n      - name: Upload Branch Results\n        uses: actions/upload-artifact@v4\n        with:\n          name: branch\n          path: branch.txt\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - main\n      - 'v*'\n    paths-ignore:\n      - 'docs/**'\n      - '*.md'\n  pull_request:\n    paths-ignore:\n      - 'docs/**'\n      - '*.md'\n\n# This allows a subsequently queued workflow run to interrupt previous runs\nconcurrency:\n  group: \"${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}\"\n  cancel-in-progress: true\n\njobs:\n  dependency-review:\n    name: Dependency Review\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - name: Check out repo\n        uses: actions/checkout@v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Dependency review\n        uses: actions/dependency-review-action@v4\n\n  test:\n    name: ${{ matrix.node-version }} ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    permissions:\n      contents: read\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [macOS-latest, windows-latest, ubuntu-latest]\n        node-version: [20, 22, 24, 25]\n        exclude:\n          - os: windows-latest\n            node-version: 22\n\n    steps:\n      - name: Check out repo\n        uses: actions/checkout@v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Setup Node ${{ matrix.node-version }}\n        uses: actions/setup-node@v6\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Install dependencies\n        run: npm i --ignore-scripts\n\n      - name: Run tests\n        run: npm run test-ci\n\n      - name: Run smoke test\n        if: >\n          matrix.os != 'windows-latest' &&\n          matrix.node-version > 14\n        run: npm run test:smoke\n\n  automerge:\n    name: Automerge Dependabot PRs\n    if: >\n        github.event_name == 'pull_request' &&\n        github.event.pull_request.user.login == 'dependabot[bot]'\n    needs: test\n    permissions:\n      pull-requests: write\n      contents: write\n    runs-on: ubuntu-latest\n    steps:\n      - uses: fastify/github-action-merge-dependabot@v3\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          exclude: 'sonic-boom,pino-std-serializers,quick-format-unescaped,fast-redact'\n"
  },
  {
    "path": ".github/workflows/lock-threads.yml",
    "content": "name: 'Lock Threads'\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n\nconcurrency:\n  group: lock\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: jsumners/lock-threads@b27edac0ac998d42b2815e122b6c24b32b568321\n        with:\n          log-output: true\n          issue-inactive-days: '30'\n          issue-comment: >\n            This issue has been automatically locked since there\n            has not been any recent activity after it was closed.\n            Please open a new issue for related bugs.\n          pr-comment: >\n            This pull request has been automatically locked since there\n            has not been any recent activity after it was closed.\n            Please open a new issue for related bugs.\n"
  },
  {
    "path": ".github/workflows/publish-release.yml",
    "content": "name: Publish release\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: 'The version number to tag and release'\n        required: true\n        type: string\n      prerelease:\n        description: 'Release as pre-release'\n        required: false\n        type: boolean\n        default: false\n\njobs:\n  release-npm:\n    runs-on: ubuntu-latest\n    environment: main\n    permissions:\n      contents: write\n      id-token: write\n    steps:\n      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4\n      - uses: actions/setup-node@v6\n        with:\n          node-version: '22'\n          registry-url: 'https://registry.npmjs.org'\n      - run: npm install npm -g\n      - run: npm install\n      - name: Change version number and sync\n        run: |\n          node build/sync-version.js ${{ inputs.version }}\n      - name: GIT commit and push all changed files\n        run: |\n          git config --global user.name \"mcollina\"\n          git config --global user.email \"hello@matteocollina.com\"\n          git commit -n -a -m \"Bumped v${{ inputs.version }}\"\n          git push origin HEAD:${{ github.ref }}\n      - run: npm publish --access public --tag ${{ inputs.prerelease == true && 'next' || 'latest' }}\n      - name: 'Create release notes'\n        run: |\n          npx @matteo.collina/release-notes -a ${{ secrets.GITHUB_TOKEN }} -t v${{ inputs.version }} -r pino -o pinojs ${{ github.event.inputs.prerelease == 'true' && '-p' || '' }} -c ${{ github.ref }}\n"
  },
  {
    "path": ".github/workflows/target-main.yml",
    "content": "name: PR Target Check\n\non:\n  pull_request_target:\n    types: [opened]\n\npermissions:\n  pull-requests: write\n\njobs:\n  comment:\n    if: ${{ github.base_ref != \"master\" }}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/github-script@v8\n        with:\n          script: |\n            github.rest.issues.createComment({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              body: '⚠️ This pull request does not target the master branch.'\n            })\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# Vim swap files\n*.swp\n\n# macOS files\n.DS_Store\n\n# editor files\n.vscode\n.idea\n\n# lock files\npackage-lock.json\npnpm-lock.yaml\nyarn.lock\n\n# 0x\n.__browserify_string_empty.js\nprofile-*\n\n# Generated files\ntest/fixtures/ts/*js\n!test/fixtures/eval/node_modules\n!test/fixtures/ts/transpile.cjs\n\n# AI assistants\nCLAUDE.md\n.claude\n.agents\n.pi\nAGENTS.md\n"
  },
  {
    "path": ".nojekyll",
    "content": ""
  },
  {
    "path": ".npmignore",
    "content": "*.png\n.github/\ndocsify/\n.nyc_output/\ncoverage/\n"
  },
  {
    "path": ".npmrc",
    "content": "package-lock=false\n"
  },
  {
    "path": ".prettierignore",
    "content": "*\n"
  },
  {
    "path": "CNAME",
    "content": "getpino.io"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Pino is an OPEN Open Source Project\n\n## What?\n\nIndividuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.\n\n## Rules\n\nBefore you start coding, please read [Contributing to projects with git](https://jrfom.com/posts/2017/03/08/a-primer-on-contributing-to-projects-with-git/). \n\nNotice that as long as you don't have commit-access to the project, you have to fork the project and open PRs from the feature branches of the forked project.\n\nThere are a few basic ground-rules for contributors:\n\n1. **No `--force` pushes** on `main` or modifying the Git history in any way after a PR has been merged.\n1. **Non-main branches** ought to be used for ongoing work.\n1. **Non-trivial changes** ought to be subject to an **internal pull-request** to solicit feedback from other contributors.\n1. All pull-requests for new features **must** target the `main` branch. PRs to fix bugs in LTS releases are also allowed.\n1. Contributors should attempt to adhere to the prevailing code-style.\n1. 100% code coverage\n\n## Releases\n\nDeclaring formal releases remains the prerogative of the project maintainer.\n\n## Changes to this arrangement\n\nThis is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change.\n\n-----------------------------------------"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016-2025 Matteo Collina, David Mark Clements and the Pino contributors listed at <https://github.com/pinojs/pino#the-team> and in the README file.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![banner](pino-banner.png)\n\n# pino\n[![npm version](https://img.shields.io/npm/v/pino)](https://www.npmjs.com/package/pino)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/pinojs/pino/ci.yml)](https://github.com/pinojs/pino/actions)\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)\n\n[Very low overhead](#low-overhead) JavaScript logger.\n\n## Documentation\n\n* [Benchmarks ⇗](/docs/benchmarks.md)\n* [API ⇗](/docs/api.md)\n* [Browser API ⇗](/docs/browser.md)\n* [Redaction ⇗](/docs/redaction.md)\n* [Child Loggers ⇗](/docs/child-loggers.md)\n* [Transports ⇗](/docs/transports.md)\n* [Diagnostics ⇗](/docs/diagnostics.md)\n* [Web Frameworks ⇗](/docs/web.md)\n* [Pretty Printing ⇗](/docs/pretty.md)\n* [Asynchronous Logging ⇗](/docs/asynchronous.md)\n* [Ecosystem ⇗](/docs/ecosystem.md)\n* [Help ⇗](/docs/help.md)\n* [Long Term Support Policy ⇗](/docs/lts.md)\n\n## Runtimes\n\n### Node.js\n\nPino is built to run on [Node.js](http://nodejs.org).\n\n### Bare\n\nPino works on [Bare](https://github.com/holepunchto/bare) with the [`pino-bare`](https://github.com/pinojs/pino-bare) compatability module.\n\n### Pear\n\nPino works on [Pear](https://docs.pears.com), which is built on [Bare](https://github.com/holepunchto/bare), with the [`pino-bare`](https://github.com/pinojs/pino-bare) compatibility module.\n\n\n## Install\n\nUsing NPM:\n```\n$ npm install pino\n```\n\nUsing YARN:\n```\n$ yarn add pino\n```\n\nIf you would like to install pino v6, refer to https://github.com/pinojs/pino/tree/v6.x.\n\n## Usage\n\n```js\nconst logger = require('pino')()\n\nlogger.info('hello world')\n\nconst child = logger.child({ a: 'property' })\nchild.info('hello child!')\n```\n\nThis produces:\n\n```\n{\"level\":30,\"time\":1531171074631,\"msg\":\"hello world\",\"pid\":657,\"hostname\":\"Davids-MBP-3.fritz.box\"}\n{\"level\":30,\"time\":1531171082399,\"msg\":\"hello child!\",\"pid\":657,\"hostname\":\"Davids-MBP-3.fritz.box\",\"a\":\"property\"}\n```\n\nFor using Pino with a web framework see:\n\n* [Pino with Fastify](docs/web.md#fastify)\n* [Pino with Express](docs/web.md#express)\n* [Pino with Hapi](docs/web.md#hapi)\n* [Pino with Restify](docs/web.md#restify)\n* [Pino with Koa](docs/web.md#koa)\n* [Pino with Node core `http`](docs/web.md#http)\n* [Pino with Nest](docs/web.md#nest)\n* [Pino with Hono](docs/web.md#hono)\n\n<a name=\"essentials\"></a>\n## Essentials\n\n### Development Formatting\n\nThe [`pino-pretty`](https://github.com/pinojs/pino-pretty) module can be used to\nformat logs during development:\n\n![pretty demo](pretty-demo.png)\n\n### Transports & Log Processing\n\nDue to Node's single-threaded event-loop, it's highly recommended that sending,\nalert triggering, reformatting, and all forms of log processing\nare conducted in a separate process or thread.\n\nIn Pino terminology, we call all log processors \"transports\" and recommend that the\ntransports be run in a worker thread using our `pino.transport` API.\n\nFor more details see our [Transports⇗](docs/transports.md) document.\n\n### Low overhead\n\nUsing minimum resources for logging is very important. Log messages\ntend to get added over time and this can lead to a throttling effect\non applications – such as reduced requests per second.\n\nIn many cases, Pino is over 5x faster than alternatives.\n\nSee the [Benchmarks](docs/benchmarks.md) document for comparisons.\n\n### Bundling support\n\nPino supports being bundled using tools like webpack or esbuild. \n\nSee [Bundling](docs/bundling.md) document for more information.\n\n<a name=\"team\"></a>\n## The Team\n\n### Matteo Collina\n\n<https://github.com/mcollina>\n\n<https://www.npmjs.com/~matteo.collina>\n\n<https://twitter.com/matteocollina>\n\n### David Mark Clements\n\n<https://github.com/davidmarkclements>\n\n<https://www.npmjs.com/~davidmarkclements>\n\n<https://twitter.com/davidmarkclem>\n\n### James Sumners\n\n<https://github.com/jsumners>\n\n<https://www.npmjs.com/~jsumners>\n\n<https://twitter.com/jsumners79>\n\n### Thomas Watson Steen\n\n<https://github.com/watson>\n\n<https://www.npmjs.com/~watson>\n\n<https://twitter.com/wa7son>\n\n## Contributing\n\nPino is an **OPEN Open Source Project**. This means that:\n\n> Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.\n\nSee the [CONTRIBUTING.md](https://github.com/pinojs/pino/blob/main/CONTRIBUTING.md) file for more details.\n\n<a name=\"acknowledgments\"></a>\n## Acknowledgments\n\nThis project was kindly sponsored by [nearForm](https://nearform.com).\nThis project is kindly sponsored by [Platformatic](https://platformatic.dev).\n\nLogo and identity designed by Cosmic Fox Design: https://www.behance.net/cosmicfox.\n\n## License\n\nLicensed under [MIT](./LICENSE).\n\n[elasticsearch]: https://www.elastic.co/products/elasticsearch\n[kibana]: https://www.elastic.co/products/kibana\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nThis document describes the management of vulnerabilities for the\nPino project and all modules within the Pino organization.\n\n## The Pino Threat Model\n\nPino is a fast JSON logger for Node.js. Understanding what Pino considers\na security vulnerability requires understanding its trust boundaries.\n\nPino's threat model builds upon the\n[Node.js threat model](https://github.com/nodejs/node/blob/main/SECURITY.md#the-nodejs-threat-model).\nWe recommend reading that document first, as Pino inherits its trust assumptions.\n\nPino trusts the applications using it and the environment that it is running in.\nThis includes all the application code, the transport, the filesystem and all\nnon-externally provided input.\n\nPino assumes all objects being logged, `logger.info(obj, message)`, are json-serializable.\nUse the `serializers` and `redact` features to sanitize them.\n\nPino is not hardened against external prototype pollution attacks, but we\nwill accept a vulnerability if Pino can be misused to cause a prototype pollution.\n\n## Reporting vulnerabilities\n\nIndividuals who find potential vulnerabilities in Pino are invited\nto report them via email at matteo.collina@gmail.com.\n\n### Strict measures when reporting vulnerabilities\n\nAvoid creating new \"informative\" reports. Only create new\nreport a potential vulnerability if you are absolutely sure this\nshould be tagged as an actual vulnerability. Be careful on the maintainers time.\n\n## Handling vulnerability reports\n\nWhen a potential vulnerability is reported, the following actions are taken:\n\n### Triage\n\n**Delay:** 5 business days\n\nWithin 5 business days, a member of the security team provides a first answer to the\nindividual who submitted the potential vulnerability. The possible responses\ncan be:\n\n* Acceptance: what was reported is considered as a new vulnerability\n* Rejection: what was reported is not considered as a new vulnerability\n* Need more information: the security team needs more information in order to evaluate what was reported.\n\nTriaging should include updating issue fields:\n* Asset - set/create the module affected by the report\n* Severity - TBD, currently left empty\n\n### Correction follow-up\n\n**Delay:** 90 days\n\nWhen a vulnerability is confirmed, a member of the security team volunteers to follow\nup on this report.\n\nWith the help of the individual who reported the vulnerability, they contact\nthe maintainers of the vulnerable package to make them aware of the\nvulnerability. The maintainers can be invited as participants to the reported issue.\n\nWith the package maintainer, they define a release date for the publication\nof the vulnerability. Ideally, this release date should not happen before\nthe package has been patched.\n\nThe report's vulnerable versions upper limit should be set to:\n* `*` if there is no fixed version available by the time of publishing the report.\n* the last vulnerable version. For example: `<=1.2.3` if a fix exists in `1.2.4`\n\n### Publication\n\n**Delay:** 90 days\n\nWithin 90 days after the triage date, the vulnerability must be made public.\n\n**Severity**: Vulnerability severity is assessed using [CVSS v.3](https://www.first.org/cvss/user-guide).\n\nIf the package maintainer is actively developing a patch, an additional delay\ncan be added with the approval of the security team and the individual who\nreported the vulnerability. \n\nAt this point, a CVE will be requested by the team.\n"
  },
  {
    "path": "benchmarks/basic.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst winston = require('winston')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst loglevel = require('./utils/wrap-log-level')(dest)\nconst plogNodeStream = pino(dest)\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', minLength: 4096 }))\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null'))\n\nprocess.env.DEBUG = 'dlog'\nconst debug = require('debug')\nconst dlog = debug('dlog')\ndlog.log = function (s) { dest.write(s) }\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst chill = winston.createLogger({\n  transports: [\n    new winston.transports.Stream({\n      stream: fs.createWriteStream('/dev/null')\n    })\n  ]\n})\n\nconst run = bench([\n  function benchBunyan (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchWinston (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log('info', 'hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchBole (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchDebug (cb) {\n    for (var i = 0; i < max; i++) {\n      dlog('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchLogLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      loglevel.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPino (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLength (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStream (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info('hello world')\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/child-child.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest).child({ a: 'property' }).child({ sub: 'child' })\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null')).child({ a: 'property' }).child({ sub: 'child' })\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\n  .child({ a: 'property' })\n  .child({ sub: 'child' })\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n}).child({ a: 'property' }).child({ sub: 'child' })\n\nconst run = bench([\n  function benchBunyanChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/child-creation.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest)\nconst plogDest = pino(pino.destination(('/dev/null')))\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst run = bench([\n  function benchBunyanCreation (cb) {\n    const child = blog.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchBoleCreation (cb) {\n    const child = bole('child')\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoCreation (cb) {\n    const child = plogDest.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthCreation (cb) {\n    const child = plogMinLength.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamCreation (cb) {\n    const child = plogNodeStream.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoCreationWithOption (cb) {\n    const child = plogDest.child({ a: 'property' }, { redact: [] })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/child.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')('child')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest).child({ a: 'property' })\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null')).child({ a: 'property' })\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n}).child({ a: 'property' })\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst run = bench([\n  function benchBunyanChild (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchBoleChild (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/deep-object.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst winston = require('winston')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest)\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\ndelete require.cache[require.resolve('../')]\n\nconst loglevel = require('./utils/wrap-log-level')(dest)\n\nconst deep = Object.assign({}, require('../package.json'), { level: 'info' })\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst chill = winston.createLogger({\n  transports: [\n    new winston.transports.Stream({\n      stream: fs.createWriteStream('/dev/null')\n    })\n  ]\n})\n\nconst run = bench([\n  function benchBunyanDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchWinstonDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchBoleDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchLogLevelDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      loglevel.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info(deep)\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/formatters.bench.js",
    "content": "'use strict'\n\nconst formatters = {\n  level (label, number) {\n    return {\n      log: {\n        level: label\n      }\n    }\n  },\n  bindings (bindings) {\n    return {\n      process: {\n        pid: bindings.pid\n      },\n      host: {\n        name: bindings.hostname\n      }\n    }\n  },\n  log (obj) {\n    return { foo: 'bar', ...obj }\n  }\n}\n\nconst bench = require('fastbench')\nconst pino = require('../')\ndelete require.cache[require.resolve('../')]\nconst pinoNoFormatters = require('../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../')]\nconst pinoFormatters = require('../')({ formatters }, pino.destination('/dev/null'))\n\nconst max = 10\n\nconst run = bench([\n  function benchPinoNoFormatters (cb) {\n    for (var i = 0; i < max; i++) {\n      pinoNoFormatters.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoFormatters (cb) {\n    for (var i = 0; i < max; i++) {\n      pinoFormatters.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/internal/custom-levels.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../../')\n\nconst base = pino(pino.destination('/dev/null'))\nconst baseCl = pino({\n  customLevels: { foo: 31 }\n}, pino.destination('/dev/null'))\nconst child = base.child({})\nconst childCl = base.child({\n  customLevels: { foo: 31 }\n})\nconst childOfBaseCl = baseCl.child({})\n\nconst max = 100\n\nconst run = bench([\n  function benchPinoNoCustomLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      base.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoCustomLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      baseCl.foo({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchChildNoCustomLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildCustomLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      childCl.foo({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildInheritedCustomLevel (cb) {\n    for (var i = 0; i < max; i++) {\n      childOfBaseCl.foo({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildCreation (cb) {\n    const child = base.child({})\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildCreationCustomLevel (cb) {\n    const child = base.child({\n      customLevels: { foo: 31 }\n    })\n    for (var i = 0; i < max; i++) {\n      child.foo({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/internal/just-pino-heavy.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../../')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plog = pino(dest)\ndelete require.cache[require.resolve('../../')]\nconst plogDest = require('../../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../../')]\nconst plogAsync = require('../../')(pino.destination({ dest: '/dev/null', sync: false }))\nconst deep = require('../../package.json')\ndeep.deep = JSON.parse(JSON.stringify(deep))\ndeep.deep.deep = JSON.parse(JSON.stringify(deep))\nconst longStr = JSON.stringify(deep)\n\nconst max = 10\n\nconst run = bench([\n  function benchPinoLongString (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestLongString (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncLongString (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncDeepObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info(deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  }\n], 1000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/internal/just-pino.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../../')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plog = pino(dest)\ndelete require.cache[require.resolve('../../')]\nconst plogDest = require('../../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../../')]\nconst plogAsync = require('../../')(pino.destination({ dest: '/dev/null', sync: false }))\nconst plogChild = plog.child({ a: 'property' })\nconst plogDestChild = plogDest.child({ a: 'property' })\nconst plogAsyncChild = plogAsync.child({ a: 'property' })\nconst plogChildChild = plog.child({ a: 'property' }).child({ sub: 'child' })\nconst plogDestChildChild = plogDest.child({ a: 'property' }).child({ sub: 'child' })\nconst plogAsyncChildChild = plogAsync.child({ a: 'property' }).child({ sub: 'child' })\n\nconst max = 10\n\nconst run = bench([\n  function benchPino (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDest (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoExtreme (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDestChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsyncChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogChildChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDestChildChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsyncChildChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildCreation (cb) {\n    const child = plog.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestChildCreation (cb) {\n    const child = plogDest.child({ a: 'property' })\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMulti (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestMulti (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncMulti (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info('hello', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoDestInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/internal/parent-vs-child.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../../')\n\nconst base = pino(pino.destination('/dev/null'))\nconst child = base.child({})\nconst childChild = child.child({})\nconst childChildChild = childChild.child({})\nconst childChildChildChild = childChildChild.child({})\nconst child2 = base.child({})\nconst baseSerializers = pino(pino.destination('/dev/null'))\nconst baseSerializersChild = baseSerializers.child({})\nconst baseSerializersChildSerializers = baseSerializers.child({})\n\nconst max = 100\n\nconst run = bench([\n  function benchPinoBase (cb) {\n    for (var i = 0; i < max; i++) {\n      base.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChild (cb) {\n    for (var i = 0; i < max; i++) {\n      child.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      childChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      childChildChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChildChildChildChild (cb) {\n    for (var i = 0; i < max; i++) {\n      childChildChildChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoChild2 (cb) {\n    for (var i = 0; i < max; i++) {\n      child2.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoBaseSerializers (cb) {\n    for (var i = 0; i < max; i++) {\n      baseSerializers.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoBaseSerializersChild (cb) {\n    for (var i = 0; i < max; i++) {\n      baseSerializersChild.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoBaseSerializersChildSerializers (cb) {\n    for (var i = 0; i < max; i++) {\n      baseSerializersChildSerializers.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/internal/redact.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../../')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plog = pino(dest)\ndelete require.cache[require.resolve('../../')]\nconst plogAsync = require('../../')(pino.destination({ dest: '/dev/null', sync: false }))\ndelete require.cache[require.resolve('../../')]\nconst plogUnsafe = require('../../')({ safe: false }, dest)\ndelete require.cache[require.resolve('../../')]\nconst plogUnsafeAsync = require('../../')(\n  { safe: false },\n  pino.destination({ dest: '/dev/null', sync: false })\n)\nconst plogRedact = pino({ redact: ['a.b.c'] }, dest)\ndelete require.cache[require.resolve('../../')]\nconst plogAsyncRedact = require('../../')(\n  { redact: ['a.b.c'] },\n  pino.destination({ dest: '/dev/null', sync: false })\n)\ndelete require.cache[require.resolve('../../')]\nconst plogUnsafeRedact = require('../../')({ redact: ['a.b.c'], safe: false }, dest)\ndelete require.cache[require.resolve('../../')]\nconst plogUnsafeAsyncRedact = require('../../')(\n  { redact: ['a.b.c'], safe: false },\n  pino.destination({ dest: '/dev/null', sync: false })\n)\n\nconst max = 10\n\n// note that \"redact me.\" is the same amount of bytes as the censor: \"[Redacted]\"\n\nconst run = bench([\n  function benchPinoNoRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plog.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogRedact.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoUnsafeNoRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogUnsafe.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoUnsafeRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogUnsafeRedact.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncNoRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsync.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoAsyncRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogAsyncRedact.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoUnsafeAsyncNoRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogUnsafeAsync.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoUnsafeAsyncRedact (cb) {\n    for (var i = 0; i < max; i++) {\n      plogUnsafeAsyncRedact.info({ a: { b: { c: 'redact me.', d: 'leave me' } } })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/long-string.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst winston = require('winston')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest)\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\n\nconst crypto = require('crypto')\n\nconst longStr = crypto.randomBytes(2000).toString()\n\nconst max = 10\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst chill = winston.createLogger({\n  transports: [\n    new winston.transports.Stream({\n      stream: fs.createWriteStream('/dev/null')\n    })\n  ]\n})\n\nconst run = bench([\n  function benchBunyan (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchWinston (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchBole (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPino (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLength (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info(longStr)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStream (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info(longStr)\n    }\n    setImmediate(cb)\n  }\n], 1000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/multi-arg.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst winston = require('winston')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst plogNodeStream = pino(dest)\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\ndelete require.cache[require.resolve('../')]\n\nconst deep = require('../package.json')\ndeep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep)))\ndeep.deep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep)))\ndeep.deep.deep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep)))\n\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\n\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\n\nconst chill = winston.createLogger({\n  transports: [\n    new winston.transports.Stream({\n      stream: fs.createWriteStream('/dev/null')\n    })\n  ]\n})\n\nconst max = 10\n\nconst run = bench([\n  function benchBunyanInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchWinstonInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log('info', 'hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchBoleInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamInterpolate (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info('hello %s', 'world')\n    }\n    setImmediate(cb)\n  },\n  function benchBunyanInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n\n  function benchWinstonInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log('info', 'hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchBoleInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamInterpolateAll (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info('hello %s %j %d', 'world', { obj: true }, 4)\n    }\n    setImmediate(cb)\n  },\n  function benchBunyanInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchWinstonInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log('info', 'hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchBoleInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamInterpolateExtra (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info('hello %s %j %d', 'world', { obj: true }, 4, { another: 'obj' })\n    }\n    setImmediate(cb)\n  },\n  function benchBunyanInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchWinstonInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.log('info', 'hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchBoleInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamInterpolateDeep (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info('hello %j', deep)\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/multistream.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst bunyan = require('bunyan')\nconst pino = require('../')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\n\nconst tenStreams = [\n  { stream: dest },\n  { stream: dest },\n  { stream: dest },\n  { stream: dest },\n  { stream: dest },\n  { level: 'debug', stream: dest },\n  { level: 'debug', stream: dest },\n  { level: 'trace', stream: dest },\n  { level: 'warn', stream: dest },\n  { level: 'fatal', stream: dest }\n]\nconst pinomsTen = pino({ level: 'debug' }, pino.multistream(tenStreams))\n\nconst fourStreams = [\n  { stream: dest },\n  { stream: dest },\n  { level: 'debug', stream: dest },\n  { level: 'trace', stream: dest }\n]\nconst pinomsFour = pino({ level: 'debug' }, pino.multistream(fourStreams))\n\nconst pinomsOne = pino({ level: 'info' }, pino.multistream(dest))\nconst blogOne = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{ stream: dest }]\n})\n\nconst blogTen = bunyan.createLogger({\n  name: 'myapp',\n  streams: tenStreams\n})\nconst blogFour = bunyan.createLogger({\n  name: 'myapp',\n  streams: fourStreams\n})\n\nconst max = 10\nconst run = bench([\n  function benchBunyanTen (cb) {\n    for (let i = 0; i < max; i++) {\n      blogTen.info('hello world')\n      blogTen.debug('hello world')\n      blogTen.trace('hello world')\n      blogTen.warn('hello world')\n      blogTen.fatal('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMSTen (cb) {\n    for (let i = 0; i < max; i++) {\n      pinomsTen.info('hello world')\n      pinomsTen.debug('hello world')\n      pinomsTen.trace('hello world')\n      pinomsTen.warn('hello world')\n      pinomsTen.fatal('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchBunyanFour (cb) {\n    for (let i = 0; i < max; i++) {\n      blogFour.info('hello world')\n      blogFour.debug('hello world')\n      blogFour.trace('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMSFour (cb) {\n    for (let i = 0; i < max; i++) {\n      pinomsFour.info('hello world')\n      pinomsFour.debug('hello world')\n      pinomsFour.trace('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchBunyanOne (cb) {\n    for (let i = 0; i < max; i++) {\n      blogOne.info('hello world')\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMSOne (cb) {\n    for (let i = 0; i < max; i++) {\n      pinomsOne.info('hello world')\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun()\n"
  },
  {
    "path": "benchmarks/object.bench.js",
    "content": "'use strict'\n\nconst bench = require('fastbench')\nconst pino = require('../')\nconst bunyan = require('bunyan')\nconst bole = require('bole')('bench')\nconst winston = require('winston')\nconst fs = require('node:fs')\nconst dest = fs.createWriteStream('/dev/null')\nconst loglevel = require('./utils/wrap-log-level')(dest)\nconst plogNodeStream = pino(dest)\ndelete require.cache[require.resolve('../')]\nconst plogDest = require('../')(pino.destination('/dev/null'))\ndelete require.cache[require.resolve('../')]\nconst plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))\nconst blog = bunyan.createLogger({\n  name: 'myapp',\n  streams: [{\n    level: 'trace',\n    stream: dest\n  }]\n})\nrequire('bole').output({\n  level: 'info',\n  stream: dest\n}).setFastTime(true)\nconst chill = winston.createLogger({\n  transports: [\n    new winston.transports.Stream({\n      stream: fs.createWriteStream('/dev/null')\n    })\n  ]\n})\n\nconst max = 10\n\nconst run = bench([\n  function benchBunyanObj (cb) {\n    for (var i = 0; i < max; i++) {\n      blog.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchWinstonObj (cb) {\n    for (var i = 0; i < max; i++) {\n      chill.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchBoleObj (cb) {\n    for (var i = 0; i < max; i++) {\n      bole.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchLogLevelObject (cb) {\n    for (var i = 0; i < max; i++) {\n      loglevel.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogDest.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoMinLengthObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogMinLength.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  },\n  function benchPinoNodeStreamObj (cb) {\n    for (var i = 0; i < max; i++) {\n      plogNodeStream.info({ hello: 'world' })\n    }\n    setImmediate(cb)\n  }\n], 10000)\n\nrun(run)\n"
  },
  {
    "path": "benchmarks/utils/generate-benchmark-doc.js",
    "content": "'use strict'\nconst { join } = require('node:path')\nconst { execSync } = require('node:child_process')\n\nconst run = (type) => {\n  process.stderr.write(`benchmarking ${type}\\n`)\n  return execSync(`node ${join(__dirname, 'runbench')} ${type} -q`)\n}\n\nconsole.log(`\n# Benchmarks\n\n\\`pino.info('hello world')\\`:\n\n\\`\\`\\`\n${run('basic')}\n\\`\\`\\`\n\n\\`pino.info({'hello': 'world'})\\`:\n\n\\`\\`\\`\n${run('object')}\n\\`\\`\\`\n\n\\`pino.info(aBigDeeplyNestedObject)\\`:\n\n\\`\\`\\`\n${run('deep-object')}\n\\`\\`\\`\n\n\\`pino.info('hello %s %j %d', 'world', {obj: true}, 4, {another: 'obj'})\\`:\n\nFor a fair comparison, [LogLevel](http://npm.im/loglevel) was extended\nto include a timestamp and [bole](http://npm.im/bole) had\n\\`fastTime\\` mode switched on.\n`)\n"
  },
  {
    "path": "benchmarks/utils/runbench.js",
    "content": "'use strict'\n\nconst { type, platform, arch, release, cpus } = require('node:os')\nconst { resolve, join } = require('node:path')\nconst spawn = require('node:child_process').spawn\nconst pump = require('pump')\nconst split = require('split2')\nconst through = require('through2')\nconst steed = require('steed')\n\nfunction usage () {\n  console.log(`\n    Pino\u001b Benchmarks\n\n    To run a benchmark, specify which to run:\n\n    ・all        ⁃ run all benchmarks (takes a while)\n    ・basic      ⁃ log a simple string\n    ・object     ⁃ logging a basic object\n    ・deep-object ⁃ logging a large object\n    ・multi-arg   ⁃ multiple log method arguments\n    ・child      ⁃ child from a parent\n    ・child-child ⁃ child from a child\n    ・child-creation ⁃ child constructor\n    ・formatters ⁃ difference between with or without formatters\n\n    Example:\n\n      node runbench basic\n  `)\n}\n\nif (!process.argv[2]) {\n  usage()\n  process.exit()\n}\n\nconst quiet = process.argv[3] === '-q'\n\nconst selectedBenchmark = process.argv[2].toLowerCase()\nconst benchmarkDir = resolve(__dirname, '..')\nconst benchmarks = {\n  basic: 'basic.bench.js',\n  object: 'object.bench.js',\n  'deep-object': 'deep-object.bench.js',\n  'multi-arg': 'multi-arg.bench.js',\n  'long-string': 'long-string.bench.js',\n  child: 'child.bench.js',\n  'child-child': 'child-child.bench.js',\n  'child-creation': 'child-creation.bench.js',\n  formatters: 'formatters.bench.js'\n}\n\nfunction runBenchmark (name, done) {\n  const benchmarkResults = {}\n  benchmarkResults[name] = {}\n\n  const processor = through(function (line, enc, cb) {\n    const [label, time] = ('' + line).split(': ')\n    const [target, iterations] = label.split('*')\n    const logger = target.replace('bench', '')\n\n    if (!benchmarkResults[name][logger]) benchmarkResults[name][logger] = []\n\n    benchmarkResults[name][logger].push({\n      time: time.replace('ms', ''),\n      iterations: iterations.replace(':', '')\n    })\n\n    cb()\n  })\n\n  if (quiet === false) console.log(`Running ${name.toUpperCase()} benchmark\\n`)\n\n  const benchmark = spawn(\n    process.argv[0],\n    [join(benchmarkDir, benchmarks[name])]\n  )\n\n  if (quiet === false) {\n    benchmark.stdout.pipe(process.stdout)\n  }\n\n  pump(benchmark.stdout, split(), processor)\n\n  benchmark.on('exit', () => {\n    console.log()\n    if (done && typeof done === 'function') done(null, benchmarkResults)\n  })\n}\n\nfunction sum (arr) {\n  let result = 0\n  for (var i = 0; i < arr.length; i += 1) {\n    result += Number.parseFloat(arr[i].time)\n  }\n  return result\n}\n\nfunction displayResults (results) {\n  if (quiet === false) console.log('==========')\n  const benchNames = Object.keys(results)\n  for (var i = 0; i < benchNames.length; i += 1) {\n    console.log(`${benchNames[i].toUpperCase()} benchmark averages`)\n    const benchmark = results[benchNames[i]]\n    const loggers = Object.keys(benchmark)\n    for (var j = 0; j < loggers.length; j += 1) {\n      const logger = benchmark[loggers[j]]\n      const average = sum(logger) / logger.length\n      console.log(`${loggers[j]} average: ${average.toFixed(3)}ms`)\n    }\n  }\n  if (quiet === false) {\n    console.log('==========')\n    console.log(\n      `System: ${type()}/${platform()} ${arch()} ${release()}`,\n      `~ ${cpus()[0].model} (cores/threads: ${cpus().length})`\n    )\n  }\n}\n\nfunction toBench (done) {\n  runBenchmark(this.name, done)\n}\n\nconst benchQueue = []\nif (selectedBenchmark !== 'all') {\n  benchQueue.push(toBench.bind({ name: selectedBenchmark }))\n} else {\n  const keys = Object.keys(benchmarks)\n  for (var i = 0; i < keys.length; i += 1) {\n    benchQueue.push(toBench.bind({ name: keys[i] }))\n  }\n}\nsteed.series(benchQueue, function (err, results) {\n  if (err) return console.error(err.message)\n  results.forEach(displayResults)\n})\n"
  },
  {
    "path": "benchmarks/utils/wrap-log-level.js",
    "content": "'use strict'\n\nconst { readFileSync } = require('node:fs')\nconst vm = require('vm')\nconst { join } = require('node:path')\nconst code = readFileSync(\n  join(__dirname, '..', '..', 'node_modules', 'loglevel', 'lib', 'loglevel.js')\n)\nconst { Console } = require('console')\n\nfunction build (dest) {\n  const sandbox = {\n    module: {},\n    console: new Console(dest, dest)\n  }\n  const context = vm.createContext(sandbox)\n\n  const script = new vm.Script(code)\n  script.runInContext(context)\n\n  const loglevel = sandbox.log\n\n  const originalFactory = loglevel.methodFactory\n  loglevel.methodFactory = function (methodName, logLevel, loggerName) {\n    const rawMethod = originalFactory(methodName, logLevel, loggerName)\n\n    return function () {\n      const time = new Date()\n      let array\n      if (typeof arguments[0] === 'string') {\n        arguments[0] = '[' + time.toISOString() + '] ' + arguments[0]\n        rawMethod.apply(null, arguments)\n      } else {\n        array = new Array(arguments.length + 1)\n        array[0] = '[' + time.toISOString() + ']'\n        for (var i = 0; i < arguments.length; i++) {\n          array[i + 1] = arguments[i]\n        }\n        rawMethod.apply(null, array)\n      }\n    }\n  }\n\n  loglevel.setLevel(loglevel.levels.INFO)\n  return loglevel\n}\n\nmodule.exports = build\n\nif (require.main === module) {\n  const loglevel = build(process.stdout)\n  loglevel.info('hello')\n  loglevel.info({ hello: 'world' })\n  loglevel.info('hello %j', { hello: 'world' })\n}\n"
  },
  {
    "path": "bin.js",
    "content": "#!/usr/bin/env node\nconsole.error(\n  '`pino` cli has been removed. Use `pino-pretty` cli instead.\\n' +\n  '\\nSee: https://github.com/pinojs/pino-pretty'\n)\nprocess.exit(1)\n"
  },
  {
    "path": "browser.js",
    "content": "'use strict'\n\nconst format = require('quick-format-unescaped')\nconst Redact = require('@pinojs/redact')\n\nmodule.exports = pino\n\nconst CENSOR = '[Redacted]'\n\nfunction handleRedactOpts (opts) {\n  if (Array.isArray(opts)) {\n    return { paths: opts, censor: CENSOR }\n  }\n  const { paths, censor = CENSOR, remove } = opts\n  if (!Array.isArray(paths)) {\n    throw Error('pino – redact must contain an array of strings')\n  }\n  return { paths, censor: remove ? undefined : censor, remove }\n}\n\nfunction buildRedactFn (redact) {\n  if (!redact) return null\n  const { paths, censor, remove } = handleRedactOpts(redact)\n  return Redact({\n    paths,\n    censor,\n    remove,\n    serialize: false\n  })\n}\n\nconst _console = pfGlobalThisOrFallback().console || {}\nconst stdSerializers = {\n  mapHttpRequest: mock,\n  mapHttpResponse: mock,\n  wrapRequestSerializer: passthrough,\n  wrapResponseSerializer: passthrough,\n  wrapErrorSerializer: passthrough,\n  req: mock,\n  res: mock,\n  err: asErrValue,\n  errWithCause: asErrValue\n}\nfunction levelToValue (level, logger) {\n  return level === 'silent'\n    ? Infinity\n    : logger.levels.values[level]\n}\nconst baseLogFunctionSymbol = Symbol('pino.logFuncs')\nconst hierarchySymbol = Symbol('pino.hierarchy')\n\nconst logFallbackMap = {\n  error: 'log',\n  fatal: 'error',\n  warn: 'error',\n  info: 'log',\n  debug: 'log',\n  trace: 'log'\n}\n\nfunction appendChildLogger (parentLogger, childLogger) {\n  const newEntry = {\n    logger: childLogger,\n    parent: parentLogger[hierarchySymbol]\n  }\n  childLogger[hierarchySymbol] = newEntry\n}\n\nfunction setupBaseLogFunctions (logger, levels, proto) {\n  const logFunctions = {}\n  levels.forEach(level => {\n    logFunctions[level] = proto[level] ? proto[level] : (_console[level] || _console[logFallbackMap[level] || 'log'] || noop)\n  })\n  logger[baseLogFunctionSymbol] = logFunctions\n}\n\nfunction shouldSerialize (serialize, serializers) {\n  if (Array.isArray(serialize)) {\n    const hasToFilter = serialize.filter(function (k) {\n      return k !== '!stdSerializers.err'\n    })\n    return hasToFilter\n  } else if (serialize === true) {\n    return Object.keys(serializers)\n  }\n\n  return false\n}\n\nfunction pino (opts) {\n  opts = opts || {}\n  opts.browser = opts.browser || {}\n\n  const transmit = opts.browser.transmit\n  if (transmit && typeof transmit.send !== 'function') { throw Error('pino: transmit option must have a send function') }\n\n  const proto = opts.browser.write || _console\n  if (opts.browser.write) opts.browser.asObject = true\n  const serializers = opts.serializers || {}\n  const serialize = shouldSerialize(opts.browser.serialize, serializers)\n  let stdErrSerialize = opts.browser.serialize\n\n  if (\n    Array.isArray(opts.browser.serialize) &&\n    opts.browser.serialize.indexOf('!stdSerializers.err') > -1\n  ) stdErrSerialize = false\n\n  const customLevels = Object.keys(opts.customLevels || {})\n  const levels = ['error', 'fatal', 'warn', 'info', 'debug', 'trace'].concat(customLevels)\n\n  if (typeof proto === 'function') {\n    levels.forEach(function (level) {\n      proto[level] = proto\n    })\n  }\n  if (opts.enabled === false || opts.browser.disabled) opts.level = 'silent'\n  const level = opts.level || 'info'\n  const logger = Object.create(proto)\n  if (!logger.log) logger.log = noop\n\n  setupBaseLogFunctions(logger, levels, proto)\n  // setup root hierarchy entry\n  appendChildLogger({}, logger)\n\n  Object.defineProperty(logger, 'levelVal', {\n    get: getLevelVal\n  })\n  Object.defineProperty(logger, 'level', {\n    get: getLevel,\n    set: setLevel\n  })\n\n  const redactFn = buildRedactFn(opts.redact)\n\n  const setOpts = {\n    transmit,\n    serialize,\n    asObject: opts.browser.asObject,\n    asObjectBindingsOnly: opts.browser.asObjectBindingsOnly,\n    formatters: opts.browser.formatters,\n    reportCaller: opts.browser.reportCaller,\n    levels,\n    timestamp: getTimeFunction(opts),\n    messageKey: opts.messageKey || 'msg',\n    onChild: opts.onChild || noop,\n    redactFn\n  }\n  logger.levels = getLevels(opts)\n  logger.level = level\n\n  logger.isLevelEnabled = function (level) {\n    if (!this.levels.values[level]) {\n      return false\n    }\n\n    return this.levels.values[level] >= this.levels.values[this.level]\n  }\n  logger.setMaxListeners = logger.getMaxListeners =\n  logger.emit = logger.addListener = logger.on =\n  logger.prependListener = logger.once =\n  logger.prependOnceListener = logger.removeListener =\n  logger.removeAllListeners = logger.listeners =\n  logger.listenerCount = logger.eventNames =\n  logger.write = logger.flush = noop\n  logger.serializers = serializers\n  logger._serialize = serialize\n  logger._stdErrSerialize = stdErrSerialize\n  logger.child = function (...args) { return child.call(this, setOpts, ...args) }\n\n  if (transmit) logger._logEvent = createLogEventShape()\n\n  function getLevelVal () {\n    return levelToValue(this.level, this)\n  }\n\n  function getLevel () {\n    return this._level\n  }\n  function setLevel (level) {\n    if (level !== 'silent' && !this.levels.values[level]) {\n      throw Error('unknown level ' + level)\n    }\n    this._level = level\n\n    set(this, setOpts, logger, 'error') // <-- must stay first\n    set(this, setOpts, logger, 'fatal')\n    set(this, setOpts, logger, 'warn')\n    set(this, setOpts, logger, 'info')\n    set(this, setOpts, logger, 'debug')\n    set(this, setOpts, logger, 'trace')\n\n    customLevels.forEach((level) => {\n      set(this, setOpts, logger, level)\n    })\n  }\n\n  function child (setOpts, bindings, childOptions) {\n    if (!bindings) {\n      throw new Error('missing bindings for child Pino')\n    }\n    childOptions = childOptions || {}\n    if (serialize && bindings.serializers) {\n      childOptions.serializers = bindings.serializers\n    }\n    const childOptionsSerializers = childOptions.serializers\n    if (serialize && childOptionsSerializers) {\n      var childSerializers = Object.assign({}, serializers, childOptionsSerializers)\n      var childSerialize = opts.browser.serialize === true\n        ? Object.keys(childSerializers)\n        : serialize\n      delete bindings.serializers\n      applySerializers([bindings], childSerialize, childSerializers, this._stdErrSerialize)\n    }\n    function Child (parent) {\n      this._childLevel = (parent._childLevel | 0) + 1\n\n      // make sure bindings are available in the `set` function\n      this.bindings = bindings\n\n      if (childSerializers) {\n        this.serializers = childSerializers\n        this._serialize = childSerialize\n      }\n      if (transmit) {\n        this._logEvent = createLogEventShape(\n          [].concat(parent._logEvent.bindings, bindings)\n        )\n      }\n    }\n    Child.prototype = this\n    const newLogger = new Child(this)\n\n    // must happen before the level is assigned\n    appendChildLogger(this, newLogger)\n    newLogger.child = function (...args) { return child.call(this, setOpts, ...args) }\n    // required to actually initialize the logger functions for any given child\n    newLogger.level = childOptions.level || this.level // allow level to be set by childOptions\n    setOpts.onChild(newLogger)\n\n    return newLogger\n  }\n  return logger\n}\n\nfunction getLevels (opts) {\n  const customLevels = opts.customLevels || {}\n\n  const values = Object.assign({}, pino.levels.values, customLevels)\n  const labels = Object.assign({}, pino.levels.labels, invertObject(customLevels))\n\n  return {\n    values,\n    labels\n  }\n}\n\nfunction invertObject (obj) {\n  const inverted = {}\n  Object.keys(obj).forEach(function (key) {\n    inverted[obj[key]] = key\n  })\n  return inverted\n}\n\npino.levels = {\n  values: {\n    fatal: 60,\n    error: 50,\n    warn: 40,\n    info: 30,\n    debug: 20,\n    trace: 10\n  },\n  labels: {\n    10: 'trace',\n    20: 'debug',\n    30: 'info',\n    40: 'warn',\n    50: 'error',\n    60: 'fatal'\n  }\n}\n\npino.stdSerializers = stdSerializers\npino.stdTimeFunctions = Object.assign({}, { nullTime, epochTime, unixTime, isoTime })\n\nfunction getBindingChain (logger) {\n  const bindings = []\n  if (logger.bindings) {\n    bindings.push(logger.bindings)\n  }\n\n  // traverse up the tree to get all bindings\n  let hierarchy = logger[hierarchySymbol]\n  while (hierarchy.parent) {\n    hierarchy = hierarchy.parent\n    if (hierarchy.logger.bindings) {\n      bindings.push(hierarchy.logger.bindings)\n    }\n  }\n\n  return bindings.reverse()\n}\n\nfunction set (self, opts, rootLogger, level) {\n  // override the current log functions with either `noop` or the base log function\n  Object.defineProperty(self, level, {\n    value: (levelToValue(self.level, rootLogger) > levelToValue(level, rootLogger)\n      ? noop\n      : rootLogger[baseLogFunctionSymbol][level]),\n    writable: true,\n    enumerable: true,\n    configurable: true\n  })\n\n  if (self[level] === noop) {\n    if (!opts.transmit) return\n\n    const transmitLevel = opts.transmit.level || self.level\n    const transmitValue = levelToValue(transmitLevel, rootLogger)\n    const methodValue = levelToValue(level, rootLogger)\n    if (methodValue < transmitValue) return\n  }\n\n  // make sure the log format is correct\n  self[level] = createWrap(self, opts, rootLogger, level)\n\n  // prepend bindings if it is not the root logger\n  const bindings = getBindingChain(self)\n  if (bindings.length === 0) {\n    // early exit in case for rootLogger\n    return\n  }\n  self[level] = prependBindingsInArguments(bindings, self[level])\n}\n\nfunction prependBindingsInArguments (bindings, logFunc) {\n  return function () {\n    return logFunc.apply(this, [...bindings, ...arguments])\n  }\n}\n\nfunction createWrap (self, opts, rootLogger, level) {\n  return (function (write) {\n    return function LOG () {\n      const ts = opts.timestamp()\n      const args = new Array(arguments.length)\n      const proto = (Object.getPrototypeOf && Object.getPrototypeOf(this) === _console) ? _console : this\n      for (var i = 0; i < args.length; i++) args[i] = arguments[i]\n\n      var argsIsSerialized = false\n      if (opts.serialize) {\n        applySerializers(args, this._serialize, this.serializers, this._stdErrSerialize)\n        argsIsSerialized = true\n      }\n      if (opts.asObject || opts.formatters) {\n        const out = asObject(this, level, args, ts, opts)\n        if (opts.reportCaller && out && out.length > 0 && out[0] && typeof out[0] === 'object') {\n          try {\n            const caller = getCallerLocation()\n            if (caller) out[0].caller = caller\n          } catch (e) {}\n        }\n        write.call(proto, ...out)\n      } else {\n        if (opts.reportCaller) {\n          try {\n            const caller = getCallerLocation()\n            if (caller) args.push(caller)\n          } catch (e) {}\n        }\n        write.apply(proto, args)\n      }\n\n      if (opts.transmit) {\n        const transmitLevel = opts.transmit.level || self._level\n        const transmitValue = levelToValue(transmitLevel, rootLogger)\n        const methodValue = levelToValue(level, rootLogger)\n        if (methodValue < transmitValue) return\n        transmit(this, {\n          ts,\n          methodLevel: level,\n          methodValue,\n          transmitLevel,\n          transmitValue: rootLogger.levels.values[opts.transmit.level || self._level],\n          send: opts.transmit.send,\n          val: levelToValue(self._level, rootLogger)\n        }, args, argsIsSerialized)\n      }\n    }\n  })(self[baseLogFunctionSymbol][level])\n}\n\nfunction asObject (logger, level, args, ts, opts) {\n  const {\n    level: levelFormatter,\n    log: logObjectFormatter = (obj) => obj\n  } = opts.formatters || {}\n  const argsCloned = args.slice()\n  let msg = argsCloned[0]\n  const logObject = {}\n\n  let lvl = (logger._childLevel | 0) + 1\n  if (lvl < 1) lvl = 1\n\n  if (ts) {\n    logObject.time = ts\n  }\n\n  if (levelFormatter) {\n    const formattedLevel = levelFormatter(level, logger.levels.values[level])\n    Object.assign(logObject, formattedLevel)\n  } else {\n    logObject.level = logger.levels.values[level]\n  }\n\n  if (opts.asObjectBindingsOnly) {\n    if (msg !== null && typeof msg === 'object') {\n      while (lvl-- && typeof argsCloned[0] === 'object') {\n        Object.assign(logObject, argsCloned.shift())\n      }\n    }\n\n    let formattedLogObject = logObjectFormatter(logObject)\n    if (opts.redactFn) {\n      formattedLogObject = opts.redactFn(formattedLogObject)\n    }\n    return [formattedLogObject, ...argsCloned]\n  } else {\n    // deliberate, catching objects, arrays\n    if (msg !== null && typeof msg === 'object') {\n      while (lvl-- && typeof argsCloned[0] === 'object') {\n        Object.assign(logObject, argsCloned.shift())\n      }\n      msg = argsCloned.length ? format(argsCloned.shift(), argsCloned) : undefined\n    } else if (typeof msg === 'string') msg = format(argsCloned.shift(), argsCloned)\n    if (msg !== undefined) logObject[opts.messageKey] = msg\n\n    let formattedLogObject = logObjectFormatter(logObject)\n    if (opts.redactFn) {\n      formattedLogObject = opts.redactFn(formattedLogObject)\n    }\n    return [formattedLogObject]\n  }\n}\n\nfunction applySerializers (args, serialize, serializers, stdErrSerialize) {\n  for (const i in args) {\n    if (stdErrSerialize && args[i] instanceof Error) {\n      args[i] = pino.stdSerializers.err(args[i])\n    } else if (typeof args[i] === 'object' && !Array.isArray(args[i]) && serialize) {\n      for (const k in args[i]) {\n        if (serialize.indexOf(k) > -1 && k in serializers) {\n          args[i][k] = serializers[k](args[i][k])\n        }\n      }\n    }\n  }\n}\n\nfunction transmit (logger, opts, args, argsIsSerialized = false) {\n  const send = opts.send\n  const ts = opts.ts\n  const methodLevel = opts.methodLevel\n  const methodValue = opts.methodValue\n  const val = opts.val\n  const bindings = logger._logEvent.bindings\n\n  if (!argsIsSerialized) {\n    applySerializers(\n      args,\n      logger._serialize || Object.keys(logger.serializers),\n      logger.serializers,\n      logger._stdErrSerialize === undefined ? true : logger._stdErrSerialize\n    )\n  }\n\n  logger._logEvent.ts = ts\n  logger._logEvent.messages = args.filter(function (arg) {\n    // bindings can only be objects, so reference equality check via indexOf is fine\n    return bindings.indexOf(arg) === -1\n  })\n\n  logger._logEvent.level.label = methodLevel\n  logger._logEvent.level.value = methodValue\n\n  send(methodLevel, logger._logEvent, val)\n\n  logger._logEvent = createLogEventShape(bindings)\n}\n\nfunction createLogEventShape (bindings) {\n  return {\n    ts: 0,\n    messages: [],\n    bindings: bindings || [],\n    level: { label: '', value: 0 }\n  }\n}\n\nfunction asErrValue (err) {\n  const obj = {\n    type: err.constructor.name,\n    msg: err.message,\n    stack: err.stack\n  }\n  for (const key in err) {\n    if (obj[key] === undefined) {\n      obj[key] = err[key]\n    }\n  }\n  return obj\n}\n\nfunction getTimeFunction (opts) {\n  if (typeof opts.timestamp === 'function') {\n    return opts.timestamp\n  }\n  if (opts.timestamp === false) {\n    return nullTime\n  }\n  return epochTime\n}\n\nfunction mock () { return {} }\nfunction passthrough (a) { return a }\nfunction noop () {}\n\nfunction nullTime () { return false }\nfunction epochTime () { return Date.now() }\nfunction unixTime () { return Math.round(Date.now() / 1000.0) }\nfunction isoTime () { return new Date(Date.now()).toISOString() } // using Date.now() for testability\n\n/* eslint-disable */\n/* istanbul ignore next */\nfunction pfGlobalThisOrFallback () {\n  function defd (o) { return typeof o !== 'undefined' && o }\n  try {\n    if (typeof globalThis !== 'undefined') return globalThis\n    Object.defineProperty(Object.prototype, 'globalThis', {\n      get: function () {\n        delete Object.prototype.globalThis\n        return (this.globalThis = this)\n      },\n      configurable: true\n    })\n    return globalThis\n  } catch (e) {\n    return defd(self) || defd(window) || defd(this) || {}\n  }\n}\n/* eslint-enable */\n\nmodule.exports.default = pino\nmodule.exports.pino = pino\n\n// Attempt to extract the user callsite (file:line:column)\n/* istanbul ignore next */\nfunction getCallerLocation () {\n  const stack = (new Error()).stack\n  if (!stack) return null\n  const lines = stack.split('\\n')\n  for (let i = 1; i < lines.length; i++) {\n    const l = lines[i].trim()\n    // skip frames from this file and internals\n    if (/(^at\\s+)?(createWrap|LOG|set\\s*\\(|asObject|Object\\.apply|Function\\.apply)/.test(l)) continue\n    if (l.indexOf('browser.js') !== -1) continue\n    if (l.indexOf('node:internal') !== -1) continue\n    if (l.indexOf('node_modules') !== -1) continue\n    // try formats like: at func (file:line:col) or at file:line:col\n    let m = l.match(/\\((.*?):(\\d+):(\\d+)\\)/)\n    if (!m) m = l.match(/at\\s+(.*?):(\\d+):(\\d+)/)\n    if (m) {\n      const file = m[1]\n      const line = m[2]\n      const col = m[3]\n      return file + ':' + line + ':' + col\n    }\n  }\n  return null\n}\n"
  },
  {
    "path": "build/sync-version.js",
    "content": "'use strict'\n\nconst fs = require('node:fs')\nconst path = require('node:path')\nlet { version } = require('../package.json')\n\nlet passedVersion = process.argv[2]\n\nif (passedVersion) {\n  passedVersion = passedVersion.trim().replace(/^v/, '')\n  if (version !== passedVersion) {\n    console.log(`Syncing version from ${version} to ${passedVersion}`)\n    version = passedVersion\n    const packageJson = require('../package.json')\n    packageJson.version = version\n    fs.writeFileSync(path.resolve('./package.json'), JSON.stringify(packageJson, null, 2) + '\\n', { encoding: 'utf-8' })\n  }\n}\n\nconst metaContent = `'use strict'\n\nmodule.exports = { version: '${version}' }\n`\n\nfs.writeFileSync(path.resolve('./lib/meta.js'), metaContent, { encoding: 'utf-8' })\n"
  },
  {
    "path": "docs/api.md",
    "content": "# API\n\n* [pino() => logger](#export)\n  * [options](#options)\n  * [destination](#destination)\n  * [destination\\[Symbol.for('pino.metadata')\\]](#metadata)\n* [Logger Instance](#logger)\n  * [logger.trace()](#trace)\n  * [logger.debug()](#debug)\n  * [logger.info()](#info)\n  * [logger.warn()](#warn)\n  * [logger.error()](#error)\n  * [logger.fatal()](#fatal)\n  * [logger.silent()](#silent)\n  * [logger.child()](#child)\n  * [logger.bindings()](#logger-bindings)\n  * [logger.setBindings()](#logger-set-bindings)\n  * [logger.flush()](#flush)\n  * [logger.level](#logger-level)\n  * [logger.isLevelEnabled()](#islevelenabled)\n  * [logger.levels](#levels)\n  * [logger\\[Symbol.for('pino.serializers')\\]](#serializers)\n  * [Event: 'level-change'](#level-change)\n  * [logger.version](#version)\n  * [logger.msgPrefix](#msgPrefix)\n* [Statics](#statics)\n  * [pino.destination()](#pino-destination)\n  * [pino.transport()](#pino-transport)\n  * [pino.multistream()](#pino-multistream)\n  * [pino.stdSerializers](#pino-stdserializers)\n  * [pino.stdTimeFunctions](#pino-stdtimefunctions)\n  * [pino.symbols](#pino-symbols)\n  * [pino.version](#pino-version)\n* [Interfaces](#interfaces)\n  * [MultiStreamRes](#multistreamres)\n  * [StreamEntry](#streamentry)\n  * [DestinationStream](#destinationstream)\n* [Types](#types)\n  * [Level](#level-1)\n* [TypeScript](#typescript)\n  * [Module Augmentation](#module-augmentation)\n  * [LogFnFields Interface](#logfnfields-interface)\n\n<a id=\"export\"></a>\n## `pino([options], [destination]) => logger`\n\nThe exported `pino` function takes two optional arguments,\n[`options`](#options) and [`destination`](#destination), and\nreturns a [logger instance](#logger).\n\n<a id=options></a>\n### `options` (Object)\n\n#### `name` (String)\n\nDefault: `undefined`\n\nThe name of the logger. When set adds a `name` field to every JSON line logged.\n\n#### `level` (String)\n\nDefault: `'info'`\n\nThe minimum level to log: Pino will not log messages with a lower level. Setting this option reduces the load, as typically, debug and trace logs are only valid for development, and not needed in production.\n\nOne of `'fatal'`, `'error'`, `'warn'`, `'info'`, `'debug'`, `'trace'` or `'silent'`.\n\nAdditional levels can be added to the instance via the `customLevels` option.\n\n* See [`customLevels` option](#opt-customlevels)\n\n<a id=opt-customlevels></a>\n\n#### `levelComparison` (\"ASC\", \"DESC\", Function)\n\nDefault: `ASC`\n\nUse this option to customize levels order.\nIn order to be able to define custom levels ordering pass a function which will accept `current` and `expected` values and return `boolean` which shows should `current` level to be shown or not.\n\n```js\nconst logger = pino({\n  levelComparison: 'DESC',\n  customLevels: {\n    foo: 20, // `foo` is more valuable than `bar`\n    bar: 10\n  },\n})\n\n// OR\n\nconst logger = pino({\n  levelComparison: function(current, expected) {\n    return current >= expected;\n  }\n})\n```\n\n#### `customLevels` (Object)\n\nDefault: `undefined`\n\nUse this option to define additional logging levels.\nThe keys of the object correspond to the namespace of the log level,\nand the values should be the numerical value of the level.\n\n```js\nconst logger = pino({\n  customLevels: {\n    foo: 35\n  }\n})\nlogger.foo('hi')\n```\n\n<a id=opt-useOnlyCustomLevels></a>\n#### `useOnlyCustomLevels` (Boolean)\n\nDefault: `false`\n\nUse this option to only use defined `customLevels` and omit Pino's levels.\nLogger's default `level` must be changed to a value in `customLevels` to use `useOnlyCustomLevels`\nWarning: this option may not be supported by downstream transports.\n\n```js\nconst logger = pino({\n  customLevels: {\n    foo: 35\n  },\n  useOnlyCustomLevels: true,\n  level: 'foo'\n})\nlogger.foo('hi')\nlogger.info('hello') // Will throw an error saying info is not found in logger object\n```\n#### `depthLimit` (Number)\n\nDefault: `5`\n\nOption to limit stringification at a specific nesting depth when logging circular objects.\n\n#### `edgeLimit` (Number)\n\nDefault: `100`\n\nOption to limit stringification of properties/elements when logging a specific object/array with circular references.\n\n<a id=\"opt-mixin\"></a>\n#### `mixin` (Function):\n\nDefault: `undefined`\n\nIf provided, the `mixin` function is called each time one of the active\nlogging methods is called. The first parameter is the value `mergeObject` or an empty object. The second parameter is the log level number.\nThe third parameter is the logger or child logger itself, which can be used to\nretrieve logger-specific context from within the `mixin` function.\nThe function must synchronously return an object. The properties of the returned object will be added to the\nlogged JSON.\n\n```js\nlet n = 0\nconst logger = pino({\n  mixin () {\n    return { line: ++n }\n  }\n})\nlogger.info('hello')\n// {\"level\":30,\"time\":1573664685466,\"pid\":78742,\"hostname\":\"x\",\"line\":1,\"msg\":\"hello\"}\nlogger.info('world')\n// {\"level\":30,\"time\":1573664685469,\"pid\":78742,\"hostname\":\"x\",\"line\":2,\"msg\":\"world\"}\n```\n\nThe result of `mixin()` is supposed to be a _new_ object. For performance reason, the object returned by `mixin()` will be mutated by pino.\nIn the following example, passing `mergingObject` argument to the first `info` call will mutate the global `mixin` object by default:\n(* See [`mixinMergeStrategy` option](#opt-mixin-merge-strategy)):\n```js\nconst mixin = {\n    appName: 'My app'\n}\n\nconst logger = pino({\n    mixin() {\n        return mixin;\n    }\n})\n\nlogger.info({\n    description: 'Ok'\n}, 'Message 1')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"appName\":\"My app\",\"description\":\"Ok\",\"msg\":\"Message 1\"}\nlogger.info('Message 2')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"appName\":\"My app\",\"description\":\"Ok\",\"msg\":\"Message 2\"}\n// Note: the second log contains \"description\":\"Ok\" text, even if it was not provided.\n```\n\nThe `mixin` method can be used to add the level label to each log message such as in the following example:\n```js\nconst logger = pino({\n  mixin(_context, level) {\n    return { 'level-label': logger.levels.labels[level] }\n  }\n})\n\nlogger.info({\n    description: 'Ok'\n}, 'Message 1')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"description\":\"Ok\",\"level-label\":\"info\",\"msg\":\"Message 1\"}\nlogger.error('Message 2')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"level-label\":\"error\",\"msg\":\"Message 2\"}\n```\n\nIf the `mixin` feature is being used merely to add static metadata to each log message,\nthen a [child logger ⇗](/docs/child-loggers.md) should be used instead. Unless your application\nneeds to concatenate values for a specific key multiple times, in which case `mixin` can be\nused to avoid the [duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat):\n\n```js\nconst logger = pino({\n  mixin (obj, num, logger) {\n    return {\n      tags: logger.tags\n    }\n  }\n})\nlogger.tags = {}\n\nlogger.addTag = function (key, value) {\n  logger.tags[key] = value\n}\n\nfunction createChild (parent, ...context) {\n  const newChild = logger.child(...context)\n  newChild.tags = { ...logger.tags }\n  newChild.addTag = function (key, value) {\n    newChild.tags[key] = value\n  }\n  return newChild\n}\n\nlogger.addTag('foo', 1)\nconst child = createChild(logger, {})\nchild.addTag('bar', 2)\nlogger.info('this will only have `foo: 1`')\nchild.info('this will have both `foo: 1` and `bar: 2`')\nlogger.info('this will still only have `foo: 1`')\n```\n\nAs of pino 7.x, when the `mixin` is used with the [`nestedKey` option](#opt-nestedkey),\nthe object returned from the `mixin` method will also be nested. Prior versions would mix\nthis object into the root.\n\n```js\nconst logger = pino({\n    nestedKey: 'payload',\n    mixin() {\n        return { requestId: requestId.currentId() }\n    }\n})\n\nlogger.info({\n    description: 'Ok'\n}, 'Message 1')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"payload\":{\"requestId\":\"dfe9a9014b\",\"description\":\"Ok\"},\"msg\":\"Message 1\"}\n```\n\n<a id=\"opt-mixin-merge-strategy\"></a>\n#### `mixinMergeStrategy` (Function):\n\nDefault: `undefined`\n\nIf provided, the `mixinMergeStrategy` function is called each time one of the active\nlogging methods is called. The first parameter is the value `mergeObject` or an empty object,\nthe second parameter is the value resulting from `mixin()` (* See [`mixin` option](#opt-mixin) or an empty object.\nThe function must synchronously return an object.\n\n```js\n// Default strategy, `mergeObject` has priority\nconst logger = pino({\n    mixin() {\n        return { tag: 'docker' }\n    },\n    // mixinMergeStrategy(mergeObject, mixinObject) {\n    //     return Object.assign(mixinMeta, mergeObject)\n    // }\n})\n\nlogger.info({\n  tag: 'local'\n}, 'Message')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"tag\":\"local\",\"msg\":\"Message\"}\n```\n\n```js\n// Custom mutable strategy, `mixin` has priority\nconst logger = pino({\n    mixin() {\n        return { tag: 'k8s' }\n    },\n    mixinMergeStrategy(mergeObject, mixinObject) {\n        return Object.assign(mergeObject, mixinObject)\n    }\n})\n\nlogger.info({\n    tag: 'local'\n}, 'Message')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"tag\":\"k8s\",\"msg\":\"Message\"}\n```\n\n```js\n// Custom immutable strategy, `mixin` has priority\nconst logger = pino({\n    mixin() {\n        return { tag: 'k8s' }\n    },\n    mixinMergeStrategy(mergeObject, mixinObject) {\n        return Object.assign({}, mergeObject, mixinObject)\n    }\n})\n\nlogger.info({\n    tag: 'local'\n}, 'Message')\n// {\"level\":30,\"time\":1591195061437,\"pid\":16012,\"hostname\":\"x\",\"tag\":\"k8s\",\"msg\":\"Message\"}\n```\n\n<a id=\"opt-redact\"></a>\n#### `redact` (Array | Object):\n\nDefault: `undefined`\n\nAs an array, the `redact` option specifies paths that should\nhave their values redacted from any log output.\n\nEach path must be a string using a syntax that corresponds to JavaScript dot and bracket notation.\n\nIf an object is supplied, three options can be specified:\n  * `paths` (array): Required. An array of paths. See [redaction - Path Syntax ⇗](/docs/redaction.md#paths) for specifics.\n  * `censor` (String|Function|Undefined): Optional. When supplied as a String the `censor` option will overwrite keys that are to be redacted. When set to `undefined` the key will be removed entirely from the object.\n    The `censor` option may also be a mapping function. The (synchronous) mapping function has the signature `(value, path) => redactedValue` and is called with the unredacted `value` and `path` to the key being redacted, as an array. For example given a redaction path of `a.b.c` the `path` argument would be `['a', 'b', 'c']`. The value returned from the mapping function becomes the applied censor value. Default: `'[Redacted]'`\n    value synchronously.\n    Default: `'[Redacted]'`\n  * `remove` (Boolean): Optional. Instead of censoring the value, remove both the key and the value. Default: `false`\n\n**WARNING**: Never allow user input to define redacted paths.\n\n* See the [redaction ⇗](/docs/redaction.md) documentation.\n* See [fast-redact#caveat ⇗](https://github.com/davidmarkclements/fast-redact#caveat)\n\n<a id=opt-hooks></a>\n#### `hooks` (Object)\n\nAn object mapping to hook functions. Hook functions allow for customizing\ninternal logger operations. Hook functions ***must*** be synchronous functions.\n\n<a id=\"logmethod\"></a>\n##### `logMethod`\n\nAllows for manipulating the parameters passed to logger methods. The signature\nfor this hook is `logMethod (args, method, level) {}`, where `args` is an array\nof the arguments that were passed to the log method and `method` is the log\nmethod itself, `level` is the log level itself. This hook ***must*** invoke the\n`method` function by using apply, like so: `method.apply(this, newArgumentsArray)`.\n\nFor example, Pino expects a binding object to be the first parameter with an\noptional string message as the second parameter. Using this hook the parameters\ncan be flipped:\n\n```js\nconst hooks = {\n  logMethod (inputArgs, method, level) {\n    if (inputArgs.length >= 2) {\n      const arg1 = inputArgs.shift()\n      const arg2 = inputArgs.shift()\n      return method.apply(this, [arg2, arg1, ...inputArgs])\n    }\n    return method.apply(this, inputArgs)\n  }\n}\n```\n\n\n<a id=\"streamWrite\"></a>\n##### `streamWrite`\n\nAllows for manipulating the _stringified_ JSON log data just before writing to various transports.\n\nThe method receives the stringified JSON and must return valid stringified JSON.\n\nFor example:\n```js\nconst hooks = {\n  streamWrite (s) {\n    return s.replaceAll('sensitive-api-key', 'XXX')\n  }\n}\n```\n\n<a id=opt-formatters></a>\n#### `formatters` (Object)\n\nAn object containing functions for formatting the shape of the log lines.\nThese functions should return a JSONifiable object and\nshould never throw. These functions allow for full customization of\nthe resulting log lines. For example, they can be used to change\nthe level key name or to enrich the default metadata.\n\n##### `level`\n\nChanges the shape of the log level. The default shape is `{ level: number }`.\nThe function takes two arguments, the label of the level (e.g. `'info'`)\nand the numeric value (e.g. `30`).\n\nps: The log level cannot be customized when using multiple transports\n\n```js\nconst formatters = {\n  level (label, number) {\n    return { level: number }\n  }\n}\n```\n\n##### `bindings`\n\nChanges the shape of the bindings. The default shape is `{ pid, hostname }`.\nThe function takes a single argument, the bindings object, which can be configured\nusing the [`base` option](#opt-base). Called once when creating logger.\n\n```js\nconst formatters = {\n  bindings (bindings) {\n    return { pid: bindings.pid, hostname: bindings.hostname }\n  }\n}\n```\n\n##### `log`\n\nChanges the shape of the log object. This function will be called every time\none of the log methods (such as `.info`) is called. All arguments passed to the\nlog method, except the message, will be passed to this function. By default, it does\nnot change the shape of the log object.\n\n```js\nconst formatters = {\n  log (object) {\n    return object\n  }\n}\n```\n\n<a id=opt-serializers></a>\n#### `serializers` (Object)\n\nDefault: `{err: pino.stdSerializers.err}`\n\nAn object containing functions for custom serialization of objects.\nThese functions should return an JSONifiable object and they\nshould never throw. When logging an object, each top-level property\nmatching the exact key of a serializer will be serialized using the defined serializer.\n\nThe serializers are applied when a property in the logged object matches a property\nin the serializers. The only exception is the `err` serializer as it is also applied in case\nthe object is an instance of `Error`, e.g. `logger.info(new Error('kaboom'))`.\nSee `errorKey` option to change `err` namespace.\n\n* See [pino.stdSerializers](#pino-stdserializers)\n\n#### `msgPrefix` (String)\n\nDefault: `undefined`\n\nThe `msgPrefix` property allows you to specify a prefix for every message of the logger and its children.\n\n```js\nconst logger = pino({\n  msgPrefix: '[HTTP] '\n})\nlogger.info('got new request!')\n// >  [HTTP] got new request!\n\nconst child = logger.child({})\nchild.info('User authenticated!')\n// >  [HTTP] User authenticated!\n```\n\n<a id=opt-base></a>\n#### `base` (Object)\n\nDefault: `{pid: process.pid, hostname: os.hostname()}`\n\nKey-value object added as child logger to each log line.\n\nSet to `undefined` to avoid adding `pid`, `hostname` properties to each log.\n\n#### `enabled` (Boolean)\n\nDefault: `true`\n\nSet to `false` to disable logging.\n\n#### `crlf` (Boolean)\n\nDefault: `false`\n\nSet to `true` to logs newline delimited JSON with `\\r\\n` instead of `\\n`.\n\n<a id=opt-timestamp></a>\n#### `timestamp` (Boolean | Function)\n\nDefault: `true`\n\nEnables or disables the inclusion of a timestamp in the\nlog message. If a function is supplied, it must synchronously return a partial JSON string\nrepresentation of the time, e.g. `,\"time\":1493426328206` (which is the default).\n\nIf set to `false`, no timestamp will be included in the output.\n\nSee [stdTimeFunctions](#pino-stdtimefunctions) for a set of available functions\nfor passing in as a value for this option.\n\nExample:\n```js\ntimestamp: () => `,\"time\":\"${new Date(Date.now()).toISOString()}\"`\n// which is equivalent to:\n// timestamp: stdTimeFunctions.isoTime\n```\n\n**Caution**: attempting to format time in-process will significantly impact logging performance.\n\n<a id=opt-messagekey></a>\n#### `messageKey` (String)\n\nDefault: `'msg'`\n\nThe string key for the 'message' in the JSON object.\n\n<a id=opt-messagekey></a>\n#### `errorKey` (String)\n\nDefault: `'err'`\n\nThe string key for the 'error' in the JSON object.\n\n<a id=opt-nestedkey></a>\n#### `nestedKey` (String)\n\nDefault: `null`\n\nIf there's a chance that objects being logged have properties that conflict with those from pino itself (`level`, `timestamp`, `pid`, etc)\nand duplicate keys in your log records are undesirable, pino can be configured with a `nestedKey` option that causes any `object`s that are logged\nto be placed under a key whose name is the value of `nestedKey`.\n\nThis way, when searching something like Kibana for values, one can consistently search under the configured `nestedKey` value instead of the root log record keys.\n\nFor example,\n```js\nconst logger = require('pino')({\n  nestedKey: 'payload'\n})\n\nconst thing = { level: 'hi', time: 'never', foo: 'bar'} // has pino-conflicting properties!\nlogger.info(thing)\n\n// logs the following:\n// {\"level\":30,\"time\":1578357790020,\"pid\":91736,\"hostname\":\"x\",\"payload\":{\"level\":\"hi\",\"time\":\"never\",\"foo\":\"bar\"}}\n```\nIn this way, logged objects' properties don't conflict with pino's standard logging properties,\nand searching for logged objects can start from a consistent path.\n\n#### `browser` (Object)\n\nBrowser only, may have `asObject` and `write` keys. This option is separately\ndocumented in the [Browser API ⇗](/docs/browser.md) documentation.\n\n* See [Browser API ⇗](/docs/browser.md)\n\n#### `transport` (Object)\n\nThe `transport` option is a shorthand for the [pino.transport()](#pino-transport) function.\nIt supports the same input options:\n```js\nrequire('pino')({\n  transport: {\n    target: '/absolute/path/to/my-transport.mjs'\n  }\n})\n\n// or multiple transports\nrequire('pino')({\n  transport: {\n    targets: [\n      { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n      { target: 'some-file-transport', options: { destination: '/dev/null' }\n    ]\n  }\n})\n```\n\nIf the transport option is supplied to `pino`, a [`destination`](#destination) parameter may not also be passed as a separate argument to `pino`:\n\n```js\npino({ transport: {}}, '/path/to/somewhere') // THIS WILL NOT WORK, DO NOT DO THIS\npino({ transport: {}}, process.stderr) // THIS WILL NOT WORK, DO NOT DO THIS\n```\n\nwhen using the `transport` option. In this case, an `Error` will be thrown.\n\n* See [pino.transport()](#pino-transport)\n\n#### `onChild` (Function)\n\nThe `onChild` function is a synchronous callback that will be called on each creation of a new child, passing the child instance as its first argument.\nAny error thrown inside the callback will be uncaught and should be handled inside the callback.\n```js\nconst parent = require('pino')({ onChild: (instance) => {\n  // Execute call back code for each newly created child.\n}})\n// `onChild` will now be executed with the new child.\nparent.child(bindings)\n```\n\n\n<a id=\"destination\"></a>\n### `destination` (Number | String | Object | DestinationStream | SonicBoomOpts | WritableStream)\n\nDefault: `pino.destination(1)` (STDOUT)\n\nThe `destination` parameter can be a file descriptor, a file path, or an\nobject with `dest` property pointing to a fd or path.\nAn ordinary Node.js `stream` file descriptor can be passed as the\ndestination (such as the result\nof `fs.createWriteStream`) but for peak log writing performance, it is strongly\nrecommended to use `pino.destination` to create the destination stream.\nNote that the `destination` parameter can be the result of `pino.transport()`.\n\n```js\n// pino.destination(1) by default\nconst stdoutLogger = require('pino')()\n\n// destination param may be in first position when no options:\nconst fileLogger = require('pino')( pino.destination('/log/path'))\n\n// use the stderr file handle to log to stderr:\nconst opts = {name: 'my-logger'}\nconst stderrLogger = require('pino')(opts, pino.destination(2))\n\n// automatic wrapping in pino.destination\nconst fileLogger = require('pino')('/log/path')\n\n// Asynchronous logging\nconst fileLogger = pino(pino.destination({ dest: '/log/path', sync: false }))\n```\n\nHowever, there are some special instances where `pino.destination` is not used as the default:\n\n+ When something, e.g a process manager, has monkey-patched `process.stdout.write`.\n\nIn these cases `process.stdout` is used instead.\n\nNote: If the parameter is a string integer, e.g. `'1'`, it will be coerced to\na number and used as a file descriptor. If this is not desired, provide a full\npath, e.g. `/tmp/1`.\n\n* See [`pino.destination`](#pino-destination)\n\n<a id=\"metadata\"></a>\n#### `destination[Symbol.for('pino.metadata')]`\n\nDefault: `false`\n\nUsing the global symbol `Symbol.for('pino.metadata')` as a key on the `destination` parameter and\nsetting the key to `true`, indicates that the following properties should be\nset on the `destination` object after each log line is written:\n\n* the last logging level as `destination.lastLevel`\n* the last logging message as `destination.lastMsg`\n* the last logging object as `destination.lastObj`\n* the last time as `destination.lastTime`, which will be the partial string returned\n  by the time function.\n* the last logger instance as `destination.lastLogger` (to support child\n  loggers)\n\nThe following is a succinct usage example:\n\n```js\nconst dest = pino.destination('/dev/null')\ndest[Symbol.for('pino.metadata')] = true\nconst logger = pino(dest)\nlogger.info({a: 1}, 'hi')\nconst { lastMsg, lastLevel, lastObj, lastTime} = dest\nconsole.log(\n  'Logged message \"%s\" at level %d with object %o at time %s',\n  lastMsg, lastLevel, lastObj, lastTime\n) // Logged message \"hi\" at level 30 with object { a: 1 } at time 1531590545089\n```\n\n<a id=\"logger\"></a>\n## Logger Instance\n\nThe logger instance is the object returned by the main exported\n[`pino`](#export) function.\n\nThe primary purpose of the logger instance is to provide logging methods.\n\nThe default logging methods are `trace`, `debug`, `info`, `warn`, `error`, and `fatal`.\n\nEach logging method has the following signature:\n`([mergingObject], [message], [...interpolationValues])`.\n\nThe parameters are explained below using the `logger.info` method but the same applies to all logging methods.\n\n### Logging Method Parameters\n\n<a id=mergingobject></a>\n#### `mergingObject` (Object)\n\nAn object can optionally be supplied as the first parameter. Each enumerable key and value\nof the `mergingObject` is copied into the JSON log line.\n\n```js\nlogger.info({MIX: {IN: true}})\n// {\"level\":30,\"time\":1531254555820,\"pid\":55956,\"hostname\":\"x\",\"MIX\":{\"IN\":true}}\n```\n\nIf the object is of type Error, it is wrapped in an object containing a property err (`{ err: mergingObject }`).\nThis allows for a unified error handling flow.\n\nOptions `serializers` and `errorKey` could be used at instantiation time to change the namespace\nfrom `err` to another string as preferred.\n\n<a id=\"message\"></a>\n#### `message` (String)\n\nA `message` string can optionally be supplied as the first parameter, or\nas the second parameter after supplying a `mergingObject`.\n\nBy default, the contents of the `message` parameter will be merged into the\nJSON log line under the `msg` key:\n\n```js\nlogger.info('hello world')\n// {\"level\":30,\"time\":1531257112193,\"msg\":\"hello world\",\"pid\":55956,\"hostname\":\"x\"}\n```\n\nThe `message` parameter takes precedence over the `mergingObject`.\nThat is, if a `mergingObject` contains a `msg` property, and a `message` parameter\nis supplied in addition, the `msg` property in the output log will be the value of\nthe `message` parameter not the value of the `msg` property on the `mergingObject`.\nSee [Avoid Message Conflict](/docs/help.md#avoid-message-conflict) for information\non how to overcome this limitation.\n\nIf no `message` parameter is provided, and the `mergingObject` is of type `Error` or it has a property named `err`, the\n`message` parameter is set to the `message` value of the error. See option `errorKey` if you want to change the namespace.\n\nThe `messageKey` option can be used at instantiation time to change the namespace\nfrom `msg` to another string as preferred.\n\nThe `message` string may contain a printf style string with support for\nthe following placeholders:\n\n* `%s` – string placeholder, every non-string value passed in will have `.toString()` called.\n* `%d` – digit placeholder\n* `%O`, `%o`, and `%j` – object placeholder\n\nValues supplied as additional arguments to the logger method will\nthen be interpolated accordingly.\n\n* See [`messageKey` pino option](#opt-messagekey)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"interpolationvalues\"></a>\n#### `...interpolationValues` (Any)\n\nAll arguments supplied after `message` are serialized and interpolated according\nto any supplied printf-style placeholders (`%s`, `%d`, `%o`|`%O`|`%j`) to form\nthe final output `msg` value for the JSON log line.\n\n```js\nlogger.info('%o hello %s', {worldly: 1}, 'world')\n// {\"level\":30,\"time\":1531257826880,\"msg\":\"{\\\"worldly\\\":1} hello world\",\"pid\":55956,\"hostname\":\"x\"}\n```\n\nSince pino v6, we do not automatically concatenate and cast to string\nconsecutive parameters:\n\n```js\nlogger.info('hello', 'world')\n// {\"level\":30,\"time\":1531257618044,\"msg\":\"hello\",\"pid\":55956,\"hostname\":\"x\"}\n// world is missing\n```\n\nHowever, it's possible to inject a hook to modify this behavior:\n\n```js\nconst pinoOptions = {\n  hooks: { logMethod }\n}\n\nfunction logMethod (args, method) {\n  if (args.length === 2) {\n    args[0] = `${args[0]} %j`\n  }\n  method.apply(this, args)\n}\n\nconst logger = pino(pinoOptions)\n```\n\n* See [`message` log method parameter](#message)\n* See [`logMethod` hook](#logmethod)\n\n<a id=\"error-serialization\"></a>\n#### Errors\n\nErrors can be supplied as either the first parameter or if already using `mergingObject` then as the `err` property on the `mergingObject`.\n\nOptions `serializers` and `errorKey` could be used at instantiation time to change the namespace\nfrom `err` to another string as preferred.\n\n> ## Note\n> This section describes the default configuration. The error serializer can be\n> mapped to a different key using the [`serializers`](#opt-serializers) option.\n```js\nlogger.info(new Error(\"test\"))\n// {\"level\":30,\"time\":1531257618044,\"msg\":\"test\",\"stack\":\"...\",\"type\":\"Error\",\"pid\":55956,\"hostname\":\"x\"}\n\nlogger.info({ err: new Error(\"test\"), otherkey: 123 }, \"some text\")\n// {\"level\":30,\"time\":1531257618044,\"err\":{\"msg\": \"test\", \"stack\":\"...\",\"type\":\"Error\"},\"msg\":\"some text\",\"pid\":55956,\"hostname\":\"x\",\"otherkey\":123}\n```\n\n<a id=\"trace\"></a>\n### `logger.trace([mergingObject], [message], [...interpolationValues])`\n\nWrite a `'trace'` level log, if the configured [`level`](#level) allows for it.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"debug\"></a>\n### `logger.debug([mergingObject], [message], [...interpolationValues])`\n\nWrite a `'debug'` level log, if the configured `level` allows for it.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"info\"></a>\n### `logger.info([mergingObject], [message], [...interpolationValues])`\n\nWrite an `'info'` level log, if the configured `level` allows for it.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"warn\"></a>\n### `logger.warn([mergingObject], [message], [...interpolationValues])`\n\nWrite a `'warn'` level log, if the configured `level` allows for it.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"error\"></a>\n### `logger.error([mergingObject], [message], [...interpolationValues])`\n\nWrite a `'error'` level log, if the configured `level` allows for it.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"fatal\"></a>\n### `logger.fatal([mergingObject], [message], [...interpolationValues])`\n\nWrite a `'fatal'` level log, if the configured `level` allows for it.\n\nSince `'fatal'` level messages are intended to be logged just before the process exiting the `fatal`\nmethod will always sync flush the destination.\nTherefore it's important not to misuse `fatal` since\nit will cause performance overhead if used for any\nother purpose than writing final log messages before\nthe process crashes or exits.\n\n* See [`mergingObject` log method parameter](#mergingobject)\n* See [`message` log method parameter](#message)\n* See [`...interpolationValues` log method parameter](#interpolationvalues)\n\n<a id=\"silent\"><a>\n### `logger.silent()`\n\nNoop function.\n\n<a id=\"child\"></a>\n### `logger.child(bindings, [options]) => logger`\n\nThe `logger.child` method allows for the creation of stateful loggers,\nwhere key-value pairs can be pinned to a logger causing them to be output\non every log line.\n\nChild loggers use the same output stream as the parent and inherit\nthe current log level of the parent at the time they are spawned.\n\nThe log level of a child is mutable. It can be set independently\nof the parent either by setting the [`level`](#level) accessor after creating\nthe child logger or using the [`options.level`](#optionslevel-string) key.\n\n<a id=\"logger-child-bindings\"></a>\n#### `bindings` (Object)\n\nAn object of key-value pairs to include in every log line output\nvia the returned child logger.\n\n```js\nconst child = logger.child({ MIX: {IN: 'always'} })\nchild.info('hello')\n// {\"level\":30,\"time\":1531258616689,\"msg\":\"hello\",\"pid\":64849,\"hostname\":\"x\",\"MIX\":{\"IN\":\"always\"}}\nchild.info('child!')\n// {\"level\":30,\"time\":1531258617401,\"msg\":\"child!\",\"pid\":64849,\"hostname\":\"x\",\"MIX\":{\"IN\":\"always\"}}\n```\n\nThe `bindings` object may contain any key except for reserved configuration keys `level` and `serializers`.\n\n##### `bindings.serializers` (Object) - DEPRECATED\n\nUse `options.serializers` instead.\n\n#### `options` (Object)\n\nOptions for child logger. These options will override the parent logger options.\n\n##### `options.level` (String)\n\nThe `level` property overrides the log level of the child logger.\nBy default, the parent log level is inherited.\nAfter the creation of the child logger, it is also accessible using the [`logger.level`](#logger-level) key.\n\n```js\nconst logger = pino()\nlogger.debug('nope') // will not log, since default level is info\nconst child = logger.child({foo: 'bar'}, {level: 'debug'})\nchild.debug('debug!') // will log as the `level` property set the level to debug\n```\n\n<a id=\"options-msgPrefix\"></a>\n##### `options.msgPrefix` (String)\n\nDefault: `undefined`\n\nThe `msgPrefix` property allows you to specify a prefix for every message of the child logger.\nBy default, the parent prefix is inherited.\nIf the parent already has a prefix, the prefix of the parent and then the child will be displayed.\n\n```js\nconst logger = pino({\n  msgPrefix: '[HTTP] '\n})\nlogger.info('got new request!')\n// >  [HTTP] got new request!\n\nconst child = logger.child({avengers: 'assemble'}, {msgPrefix: '[Proxy] '})\nchild.info('message proxied!')\n// >  [HTTP] [Proxy] message proxied!\n```\n\n##### `options.redact` (Array | Object)\n\nSetting `options.redact` to an array or object will override the parent `redact` options. To remove `redact` options inherited from the parent logger set this value as an empty array (`[]`).\n\n```js\nconst logger = require('pino')({ redact: ['hello'] })\nlogger.info({ hello: 'world' })\n// {\"level\":30,\"time\":1625794363403,\"pid\":67930,\"hostname\":\"x\",\"hello\":\"[Redacted]\"}\nconst child = logger.child({ foo: 'bar' }, { redact: ['foo'] })\nlogger.info({ hello: 'world' })\n// {\"level\":30,\"time\":1625794553558,\"pid\":67930,\"hostname\":\"x\",\"hello\":\"world\", \"foo\": \"[Redacted]\" }\n```\n\n* See [`redact` option](#opt-redact)\n\n##### `options.serializers` (Object)\n\nChild loggers inherit the [serializers](#opt-serializers) from the parent logger.\n\nSetting the `serializers` key of the `options` object will override\nany configured parent serializers.\n\n```js\nconst logger = require('pino')()\nlogger.info({test: 'will appear'})\n// {\"level\":30,\"time\":1531259759482,\"pid\":67930,\"hostname\":\"x\",\"test\":\"will appear\"}\nconst child = logger.child({}, {serializers: {test: () => `child-only serializer`}})\nchild.info({test: 'will be overwritten'})\n// {\"level\":30,\"time\":1531259784008,\"pid\":67930,\"hostname\":\"x\",\"test\":\"child-only serializer\"}\n```\n\n* See [`serializers` option](#opt-serializers)\n* See [pino.stdSerializers](#pino-stdSerializers)\n\n<a id=\"logger-bindings\"></a>\n### `logger.bindings()`\n\nReturns an object containing all the current bindings, cloned from the ones passed in via `logger.child()`.\n```js\nconst child = logger.child({ foo: 'bar' })\nconsole.log(child.bindings())\n// { foo: 'bar' }\nconst anotherChild = child.child({ MIX: { IN: 'always' } })\nconsole.log(anotherChild.bindings())\n// { foo: 'bar', MIX: { IN: 'always' } }\n```\n\n<a id=\"logger-set-bindings\"></a>\n### `logger.setBindings(bindings)`\n\nAdds to the bindings of this logger instance.\n\n**Note:** Does not overwrite bindings. Can potentially result in duplicate keys in\nlog lines.\n\n* See [`bindings` parameter in `logger.child`](#logger-child-bindings)\n\n<a id=\"flush\"></a>\n### `logger.flush([cb])`\n\nFlushes the content of the buffer when using `pino.destination({\nsync: false })`.\n\nThis is an asynchronous, best used as fire and forget, operation.\n\nThe use case is primarily for asynchronous logging, which may buffer\nlog lines while others are being written. The `logger.flush` method can be\nused to flush the logs\non a long interval, say ten seconds. Such a strategy can provide an\noptimum balance between extremely efficient logging at high demand periods\nand safer logging at low demand periods.\n\nIf there is a need to wait for the logs to be flushed, a callback should be used.\n\n**Note:** `flush()` does not work when using `pino-pretty`. See\n[Flush Limitations with `pino-pretty`](/docs/asynchronous.md) for more details.\n\n* See [`destination` parameter](#destination)\n* See [Asynchronous Logging ⇗](./asynchronous.md)\n\n<a id=\"logger-level\"></a>\n### `logger.level` (String) [Getter/Setter]\n\nSet this property to the desired logging level.\n\nThe core levels and their values are as follows:\n\n|            |       |       |      |      |       |       |          |\n|:-----------|-------|-------|------|------|-------|-------|---------:|\n| **Level:** | trace | debug | info | warn | error | fatal | silent   |\n| **Value:** | 10    | 20    | 30   | 40   | 50    | 60    | Infinity |\n\nThe logging level is a *minimum* level based on the associated value of that level.\n\nFor instance if `logger.level` is `info` *(30)* then `info` *(30)*, `warn` *(40)*, `error` *(50)*, and `fatal` *(60)* log methods will be enabled but the `trace` *(10)* and `debug` *(20)* methods, being less than 30, will not.\n\nThe `silent` logging level is a specialized level that will disable all logging,\nthe `silent` log method is a noop function.\n\n<a id=\"islevelenabled\"></a>\n### `logger.isLevelEnabled(level)`\n\nA utility method for determining if a given log level will write to the destination.\n\n#### `level` (String)\n\nThe given level to check against:\n\n```js\nif (logger.isLevelEnabled('debug')) logger.debug('conditional log')\n```\n\n#### `levelLabel` (String)\n\nDefines the method name of the new level.\n\n* See [`logger.level`](#level)\n\n#### `levelValue` (Number)\n\nDefines the associated minimum threshold value for the level, and\ntherefore where it sits in order of priority among other levels.\n\n* See [`logger.level`](#level)\n\n<a id=\"levelVal\"></a>\n### `logger.levelVal` (Number)\n\nSupplies the integer value for the current logging level.\n\n```js\nif (logger.levelVal === 30) {\n  console.log('logger level is `info`')\n}\n```\n\n<a id=\"levels\"></a>\n### `logger.levels` (Object)\n\nLevels are mapped to values to determine the minimum threshold that a\nlogging method should be enabled at (see [`logger.level`](#level)).\n\nThe `logger.levels` property holds the mappings between levels and values,\nand vice versa.\n\n```sh\n$ node -p \"require('pino')().levels\"\n```\n\n```js\n{ labels:\n   { '10': 'trace',\n     '20': 'debug',\n     '30': 'info',\n     '40': 'warn',\n     '50': 'error',\n     '60': 'fatal' },\n  values:\n   { fatal: 60, error: 50, warn: 40, info: 30, debug: 20, trace: 10 } }\n```\n\n* See [`logger.level`](#level)\n\n<a id=\"serializers\"></a>\n### logger\\[Symbol.for('pino.serializers')\\]\n\nReturns the serializers as applied to the current logger instance. If a child logger did not\nregister its own serializer upon instantiation the serializers of the parent will be returned.\n\n<a id=\"level-change\"></a>\n### Event: 'level-change'\n\nThe logger instance is also an [`EventEmitter ⇗`](https://nodejs.org/dist/latest/docs/api/events.html#events_class_eventemitter)\n\nA listener function can be attached to a logger via the `level-change` event\n\nThe listener is passed five arguments:\n\n* `levelLabel` – the new level string, e.g `trace`\n* `levelValue` – the new level number, e.g `10`\n* `previousLevelLabel` – the prior level string, e.g `info`\n* `previousLevelValue` – the prior level number, e.g `30`\n* `logger` – the logger instance from which the event originated\n\n```js\nconst logger = require('pino')()\nlogger.on('level-change', (lvl, val, prevLvl, prevVal) => {\n  console.log('%s (%d) was changed to %s (%d)', prevLvl, prevVal, lvl, val)\n})\nlogger.level = 'trace' // trigger event\n```\n\nPlease note that due to a [known bug](https://github.com/pinojs/pino/issues/1006), every `logger.child()` call will\nfire a `level-change` event. These events can be ignored by writing an event handler like:\n\n```js\nconst logger = require('pino')()\nlogger.on('level-change', function (lvl, val, prevLvl, prevVal, instance) {\n  if (logger !== instance) {\n    return\n  }\n  console.log('%s (%d) was changed to %s (%d)', prevLvl, prevVal, lvl, val)\n})\nlogger.child({}); // trigger an event by creating a child instance, notice no console.log\nlogger.level = 'trace' // trigger event using actual value change, notice console.log\n```\n\n<a id=\"version\"></a>\n### `logger.version` (String)\n\nExposes the Pino package version. Also available on the exported `pino` function.\n\n* See [`pino.version`](#pino-version)\n\n<a id=\"msgPrefix\"></a>\n### `logger.msgPrefix` (String|Undefined)\n\nExposes the cumulative `msgPrefix` of the logger.\n\n* See [`options.msgPrefix`](#options-msgPrefix)\n\n## Statics\n\n<a id=\"pino-destination\"></a>\n### `pino.destination([opts]) => SonicBoom`\n\nCreate a Pino Destination instance: a stream-like object with\nsignificantly more throughput than a standard Node.js stream.\n\n```js\nconst pino = require('pino')\nconst logger = pino(pino.destination('./my-file'))\nconst logger2 = pino(pino.destination())\nconst logger3 = pino(pino.destination({\n  dest: './my-file',\n  minLength: 4096, // Buffer before writing\n  sync: false // Asynchronous logging, the default\n}))\nconst logger4 = pino(pino.destination({\n  dest: './my-file2',\n  sync: true // Synchronous logging\n}))\n```\n\nThe `pino.destination` method may be passed a file path or a numerical file descriptor.\nBy default, `pino.destination` will use `process.stdout.fd` (1) as the file descriptor.\n\n`pino.destination` is implemented on [`sonic-boom` ⇗](https://github.com/mcollina/sonic-boom).\n\nA `pino.destination` instance can also be used to reopen closed files\n(for example, for some log rotation scenarios), see [Reopening log files](/docs/help.md#reopening).\n\n* See [`destination` parameter](#destination)\n* See [`sonic-boom` ⇗](https://github.com/mcollina/sonic-boom)\n* See [Reopening log files](/docs/help.md#reopening)\n* See [Asynchronous Logging ⇗](/docs/asynchronous.md)\n\n<a id=\"pino-transport\"></a>\n### `pino.transport(options) => ThreadStream`\n\nCreate a stream that routes logs to a worker thread that\nwraps around a [Pino Transport](/docs/transports.md).\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'some-transport',\n  options: { some: 'options for', the: 'transport' }\n})\npino(transport)\n```\n\nMultiple transports may also be defined, and specific levels can be logged to each transport:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [{\n    level: 'info',\n    target: 'pino-pretty' // must be installed separately\n  }, {\n    level: 'trace',\n    target: 'pino/file',\n    options: { destination: '/path/to/store/logs' }\n  }]\n})\npino(transport)\n```\n\nA pipeline could also be created to transform log lines _before_ sending them:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  pipeline: [{\n    target: 'pino-syslog' // must be installed separately\n  }, {\n    target: 'pino-socket' // must be installed separately\n  }]\n})\npino(transport)\n```\n\nMultiple transports can now be defined to include pipelines:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [{\n    level: 'info',\n    target: 'pino-pretty' // must be installed separately\n  }, {\n    level: 'trace',\n    target: 'pino/file',\n    options: { destination: '/path/to/store/logs' }\n  }, {\n    pipeline: [{\n      target: 'pino-syslog' // must be installed separately\n    }, {\n      target: 'pino-socket' // must be installed separately\n    }]\n  }\n  ]\n})\npino(transport)\n```\n\nIf `WeakRef`, `WeakMap`, and `FinalizationRegistry` are available in the current runtime (v14.5.0+), then the thread\nwill be automatically terminated in case the stream or logger goes out of scope.\nThe `transport()` function adds a listener to `process.on('beforeExit')` and `process.on('exit')` to ensure the worker\nis flushed and all data synced before the process exits.\n\nNote that calling `process.exit()` on the main thread will stop the event loop on the main thread from turning. As a result,\nusing `console.log` and `process.stdout` after the main thread called `process.exit()` will not produce any output.\n\nIf you are embedding/integrating pino within your framework, you will need to make pino aware of the script that is calling it,\nlike so:\n\n```js\nconst pino = require('pino')\nconst getCaller = require('get-caller-file')\n\nmodule.exports = function build () {\n  const logger = pino({\n    transport: {\n      caller: getCaller(),\n      target: 'transport',\n      options: { destination: './destination' }\n    }\n  })\n  return logger\n}\n```\n\nNote that _any `'error'`_ event emitted by the transport must be considered a fatal error and the process must be terminated.\nError events are not recoverable.\n\nFor more on transports, how they work, and how to create them see the [`Transports documentation`](/docs/transports.md).\n\n* See [`Transports`](/docs/transports.md)\n* See [`thread-stream` ⇗](https://github.com/mcollina/thread-stream)\n\n#### Options\n\n* `target`:  The transport to pass logs through. This may be an installed module name or an absolute path.\n* `options`:  An options object which is serialized (see [Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)), passed to the worker thread, parsed and then passed to the exported transport function.\n* `worker`: [Worker thread](https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options) configuration options. Additionally, the `worker` option supports `worker.autoEnd`. If this is set to `false` logs will not be flushed on process exit. It is then up to the developer to call `transport.end()` to flush logs.\n* `targets`: May be specified instead of `target`. Must be an array of transport configurations and/or pipelines. Transport configurations include the aforementioned `options` and `target` options plus a `level` option which will send only logs above a specified level to that transport. If `level` is omitted, it defaults to `info`.\n* `pipeline`: May be specified instead of `target`. Must be an array of transport configurations. Transport configurations include the aforementioned `options` and `target` options. All intermediate steps in the pipeline _must_ be `Transform` streams and not `Writable`.\n* `dedupe`: See [pino.multistream options](#pino-multistream)\n\nNotes:\n- The top-level `level` in `pino.transport({ ... })` is not used for filtering.\n- With a single `target` (or a single `pipeline`), filtering is controlled by `logger.level`.\n- Per-transport level filtering is applied when using `targets` (multi-destination mode).\n\n<a id=\"pino-multistream\"></a>\n\n### `pino.multistream(streamsArray, opts) => MultiStreamRes`\n\nCreate a stream composed by multiple destination streams and returns an\nobject implementing the [MultiStreamRes](#multistreamres) interface.\n\n```js\nvar fs = require('node:fs')\nvar pino = require('pino')\nvar pretty = require('pino-pretty')\nvar streams = [\n  {stream: fs.createWriteStream('/tmp/info.stream.out')},\n  {stream: pretty() },\n  {level: 'debug', stream: fs.createWriteStream('/tmp/debug.stream.out')},\n  {level: 'fatal', stream: fs.createWriteStream('/tmp/fatal.stream.out')}\n]\n\nvar log = pino({\n  level: 'debug' // this MUST be set at the lowest level of the\n                 // destinations\n}, pino.multistream(streams))\n\nlog.debug('this will be written to /tmp/debug.stream.out')\nlog.info('this will be written to /tmp/debug.stream.out and /tmp/info.stream.out')\nlog.fatal('this will be written to /tmp/debug.stream.out, /tmp/info.stream.out and /tmp/fatal.stream.out')\n```\n\nIn order for `multistream` to work, the log level __must__ be set to the lowest level used in the streams array. Default is `info`.\n\n#### Options\n\n* `levels`:  Pass custom log level definitions to the instance as an object.\n\n+ `dedupe`: Set this to `true` to send logs only to the stream with the higher level. Default: `false`\n\n    `dedupe` flag can be useful for example when using `pino.multistream` to redirect `error` logs to `process.stderr` and others to `process.stdout`:\n\n    ```js\n    var pino = require('pino')\n    var multistream = pino.multistream\n    var streams = [\n      {level: 'debug', stream: process.stdout},\n      {level: 'error', stream: process.stderr},\n    ]\n\n    var opts = {\n        levels: {\n            silent: Infinity,\n            fatal: 60,\n            error: 50,\n            warn: 50,\n            info: 30,\n            debug: 20,\n            trace: 10\n        },\n        dedupe: true,\n    }\n\n    var log = pino({\n      level: 'debug' // this MUST be set at the lowest level of the\n                    // destinations\n    }, multistream(streams, opts))\n\n    log.debug('this will be written ONLY to process.stdout')\n    log.info('this will be written ONLY to process.stdout')\n    log.error('this will be written ONLY to process.stderr')\n    log.fatal('this will be written ONLY to process.stderr')\n    ```\n\n<a id=\"pino-stdserializers\"></a>\n### `pino.stdSerializers` (Object)\n\nThe `pino.stdSerializers` object provides functions for serializing objects common to many projects. The standard serializers are directly imported from [pino-std-serializers](https://github.com/pinojs/pino-std-serializers).\n\n* See [pino-std-serializers ⇗](https://github.com/pinojs/pino-std-serializers)\n\n<a id=\"pino-stdtimefunctions\"></a>\n### `pino.stdTimeFunctions` (Object)\n\nThe [`timestamp`](#opt-timestamp) option can accept a function that determines the\n`timestamp` value in a log line.\n\nThe `pino.stdTimeFunctions` object provides a very small set of common functions for generating the\n`timestamp` property. These consist of the following\n\n* `pino.stdTimeFunctions.epochTime`: Milliseconds since Unix epoch (Default)\n* `pino.stdTimeFunctions.unixTime`: Seconds since Unix epoch\n* `pino.stdTimeFunctions.nullTime`: Clears timestamp property (Used when `timestamp: false`)\n* `pino.stdTimeFunctions.isoTime`: ISO 8601-formatted time in UTC\n* `pino.stdTimeFunctions.isoTimeNano`: RFC 3339-formatted time in UTC with nanosecond precision\n\n* See [`timestamp` option](#opt-timestamp)\n\n<a id=\"pino-symbols\"></a>\n### `pino.symbols` (Object)\n\nFor integration purposes with ecosystem and third-party libraries `pino.symbols`\nexposes the symbols used to hold non-public state and methods on the logger instance.\n\nAccess to the symbols allows logger state to be adjusted, and methods to be overridden or\nproxied for performant integration where necessary.\n\nThe `pino.symbols` object is intended for library implementers and shouldn't be utilized\nfor general use.\n\n<a id=\"pino-version\"></a>\n### `pino.version` (String)\n\nExposes the Pino package version. Also available on the logger instance.\n\n* See [`logger.version`](#version)\n\n## Interfaces\n<a id=\"pino-multistreamres\"></a>\n\n### `MultiStreamRes`\n  Properties:\n\n  * `write(data)`\n    - `data` Object | string\n    - Returns: void\n\n Write `data` onto the streams held by the current instance.\n *  `add(dest)`\n    - `dest` [StreamEntry](#streamentry) | [DestinationStream](#destinationstream)\n    - Returns: [MultiStreamRes](#multistreamres)\n\n Add `dest` stream to the array of streams of the current instance.\n *  `flushSync()`\n    - Returns: `undefined`\n\n Call `flushSync` on each stream held by the current instance.\n\n * `lastId`\n   - number\n\n The ID assigned to the last stream assigned to the current instance.\n * `minLevel`\n   - number\n\n The minimum level amongst all the streams held by the current instance.\n\n * `remove(id)`\n   - `id` [number]\n\n Removes a stream from the array of streams of the current instance using its assigned ID.\n * `streams`\n    - Returns: [StreamEntry[]](#streamentry)\n\n The array of streams currently held by the current instance.\n * `clone(level)`\n    - `level` [Level](#level-1)\n    - Returns: [MultiStreamRes](#multistreamres)\n\n Returns a cloned object of the current instance but with the provided `level`.\n\n### `StreamEntry`\n  Properties:\n\n  * `stream`\n    - DestinationStream\n  * `level`\n    - Optional: [Level](#level-1)\n\n### `DestinationStream`\n  Properties:\n\n  * `write(msg)`\n    - `msg` string\n\n## Types\n### `Level`\n\n  * Values: `\"fatal\"` | `\"error\"` | `\"warn\"` | `\"info\"` | `\"debug\"` | `\"trace\"`\n\n## TypeScript\n\n### Module Augmentation\n\nPino supports TypeScript module augmentation to extend its type definitions. This allows you to customize the logging behavior to fit your application's specific requirements.\n\n#### `LogFnFields` Interface\n\nThe `LogFnFields` interface can be augmented to control what fields are allowed in logging method objects. This is particularly useful for:\n\n- Preventing certain fields from being logged (for security or compliance reasons)\n- Enforcing specific field types across your application\n- Enforcing consistent structured logging\n\n##### Banning Fields\n\nYou can ban specific fields from being passed to logging methods by setting them to `never`. This helps prevent users from unintentionally overriding fields that are already set in the logger's `base` option, or clarifies that these fields are predefined.\n\n```typescript\ndeclare module \"pino\" {\n  interface LogFnFields {\n    service?: never;\n    version?: never;\n  }\n}\n\n\n// These will now cause TypeScript errors\nlogger.info({ service: 'other-api', message: 'success' })   // ❌\nlogger.info({ message: 'success' })     // ✅\n```\n\n##### Enforcing Field Types\n\nYou can also enforce specific types for certain fields:\n\n```typescript\ndeclare module \"pino\" {\n  interface LogFnFields {\n    userId?: string;\n    requestId?: string;\n  }\n}\n\n// These will cause TypeScript errors\nlogger.info({ userId: 123 })           // ❌ Error: userId must be string\nlogger.info({ requestId: null })       // ❌ Error: requestId must be string\n\n// This works fine\nlogger.info({ userId: '123' })     // ✅ Works fine\n```\n\n##### Enforcing Structured Logging\n\nRequired fields (non-optional) enforce consistent structured logging by requiring specific fields in all log objects:\n\n```typescript\ndeclare module \"pino\" {\n  interface LogFnFields {\n    userId: string\n  }\n}\n\nlogger.info({ userId: '123' }) // ✅ Works fine\nlogger.info({}) // ❌ Property 'userId' is missing in type '{}'\n```\n\n**Note**: Required fields will cause TypeScript errors when logging certain types like `Error` objects that don't contain the required properties:\n\n```typescript\nlogger.error(new Error('test')) // ❌ Property 'userId' is missing in type 'Error'\n```\n\nThis ensures that all log entries include required context fields, promoting consistent logging practices.\n"
  },
  {
    "path": "docs/asynchronous.md",
    "content": "# Asynchronous Logging\n\nAsynchronous logging enables the minimum overhead of Pino.\nAsynchronous logging works by buffering log messages and writing them in larger chunks.\n\n```js\nconst pino = require('pino')\nconst logger = pino(pino.destination({\n  dest: './my-file', // omit for stdout\n  minLength: 4096, // Buffer before writing\n  sync: false // Asynchronous logging\n}))\n```\n\nIt's always possible to turn on synchronous logging by passing `sync: true`. \nIn this mode of operation, log messages are directly written to the\noutput stream as the messages are generated with a _blocking_ operation.\n\n* See [`pino.destination`](/docs/api.md#pino-destination)\n* `pino.destination` is implemented on [`sonic-boom` ⇗](https://github.com/mcollina/sonic-boom).\n\n### AWS Lambda\n\nAsynchronous logging is disabled by default on AWS Lambda or any other environment\nthat modifies `process.stdout`. If forcefully turned on, we recommend calling `dest.flushSync()` at the end\nof each function execution to avoid losing data.\n\n## Caveats\n\nAsynchronous logging has a couple of important caveats:\n\n* As opposed to the synchronous mode, there is not a one-to-one relationship between\n  calls to logging methods (e.g. `logger.info`) and writes to a log file\n* There is a possibility of the most recently buffered log messages being lost\n  in case of a system failure, e.g. a power cut.\n\n### Flush Limitations with `pino-pretty`\n\nThe `logger.flush()` method does not work when using `pino-pretty` because:\n\n1. **Transport Architecture**: `pino-pretty` runs in a separate worker thread via the transport mechanism.\n\n2. **Buffer Flow**: When you call `logger.flush()`, it flushes the SonicBoom destination in the main thread, but the logs remain queued in the thread-stream worker waiting to be processed by `pino-pretty`.\n\n3. **No Cross-Thread Flush**: The flush operation never propagates through to the worker thread where the pretty printer is processing the output.\n\nThis means that even with `logger.flush()`, your formatted logs may not appear immediately, and the flush will only ensure the main thread buffer is written, not the formatted output.\n\nSee also:\n\n* [`pino.destination` API](/docs/api.md#pino-destination)\n* [`destination` parameter](/docs/api.md#destination)\n"
  },
  {
    "path": "docs/benchmarks.md",
    "content": "\n# Benchmarks\n\n`pino.info('hello world')`:\n\n```\n\nBASIC benchmark averages\nBunyan average: 377.434ms\nWinston average: 270.249ms\nBole average: 172.690ms\nDebug average: 220.527ms\nLogLevel average: 222.802ms\nPino average: 114.801ms\nPinoMinLength average: 70.968ms\nPinoNodeStream average: 159.192ms\n\n```\n\n`pino.info({'hello': 'world'})`:\n\n```\n\nOBJECT benchmark averages\nBunyanObj average: 410.379ms\nWinstonObj average: 273.120ms\nBoleObj average: 185.069ms\nLogLevelObject average: 433.425ms\nPinoObj average: 119.315ms\nPinoMinLengthObj average: 76.968ms\nPinoNodeStreamObj average: 164.268ms\n\n```\n\n`pino.info(aBigDeeplyNestedObject)`:\n\n```\n\nDEEP-OBJECT benchmark averages\nBunyanDeepObj average: 1.839ms\nWinstonDeepObj average: 5.604ms\nBoleDeepObj average: 3.422ms\nLogLevelDeepObj average: 11.716ms\nPinoDeepObj average: 2.256ms\nPinoMinLengthDeepObj average: 2.240ms\nPinoNodeStreamDeepObj average: 2.595ms\n\n```\n\n`pino.info('hello %s %j %d', 'world', {obj: true}, 4, {another: 'obj'})`:\n\nFor a fair comparison, [LogLevel](http://npm.im/loglevel) was extended\nto include a timestamp and [bole](http://npm.im/bole) had\n`fastTime` mode switched on.\n\n"
  },
  {
    "path": "docs/browser.md",
    "content": "# Browser API\n\nPino is compatible with [`browserify`](https://npm.im/browserify) for browser-side usage:\n\nThis can be useful with isomorphic/universal JavaScript code.\n\nBy default, in the browser,\n`pino` uses corresponding [Log4j](https://en.wikipedia.org/wiki/Log4j) `console` methods (`console.error`, `console.warn`, `console.info`, `console.debug`, `console.trace`) and uses `console.error` for any `fatal` level logs.\n\n## Options\n\nPino can be passed a `browser` object in the options object,\nwhich can have the following properties:\n\n### `asObject` (Boolean)\n\n```js\nconst pino = require('pino')({browser: {asObject: true}})\n```\n\nThe `asObject` option will create a pino-like log object instead of\npassing all arguments to a console method, for instance:\n\n```js\npino.info('hi') // creates and logs {msg: 'hi', level: 30, time: <ts>}\n```\n\nWhen `write` is set, `asObject` will always be `true`.\n\n### `asObjectBindingsOnly` (Boolean)\n\n```js\nconst pino = require('pino')({browser: {asObjectBindingsOnly: true}})\n```\n\nThe `asObjectBindingsOnly` option is similar to `asObject` but will keep the message\nand arguments unformatted. This allows to defer formatting the message to the\nactual call to `console` methods, where browsers then have richer formatting in\ntheir devtools than when pino will format the message to a string first.\n\n```js\npino.info('hello %s', 'world') // creates and logs {level: 30, time: <ts>}, 'hello %s', 'world'\n```\n\n### `formatters` (Object)\n\nAn object containing functions for formatting the shape of the log lines. When provided, it enables the logger to produce a pino-like log object with customized formatting. Currently, it supports formatting for the `level` object only.\n\n##### `level`\n\nChanges the shape of the log level. The default shape is `{ level: number }`.\nThe function takes two arguments, the label of the level (e.g. `'info'`)\nand the numeric value (e.g. `30`).\n\n```js\nconst formatters = {\n  level (label, number) {\n    return { level: number }\n  }\n}\n```\n\n\n### `reportCaller` (Boolean)\n\nAttempts to capture and include the originating callsite (file:line:column) for each log call in the browser logger.\n\n- When used together with `asObject` (or when `formatters` are provided), the callsite is added as a `caller` string property on the emitted log object.\n- In the default mode (non‑object), the callsite string is appended as the last argument passed to the corresponding `console` method. This makes the location visible in the console output even though the console’s clickable header still points to Pino internals.\n\n```js\n// Object mode: adds `caller` to the log object\nconst pino = require('pino')({\n  browser: {\n    asObject: true,\n    reportCaller: true\n  }\n})\n\npino.info('hello')\n// -> { level: 30, msg: 'hello', time: <ts>, caller: '/path/to/file.js:10:15' }\n\n// Default mode: appends the caller string as the last console argument\nconst pino2 = require('pino')({\n  browser: {\n    reportCaller: true\n  }\n})\n\npino2.info('hello')\n// -> console receives: 'hello', '/path/to/file.js:10:15'\n```\n\nNotes:\n\n- This is a best‑effort feature that parses the JavaScript Error stack. Stack formats vary across engines.\n- The clickable link shown by devtools for a console message is determined by where `console.*` is invoked and cannot be changed by libraries; `reportCaller` surfaces the user callsite alongside the log message.\n\n\n### `write` (Function | Object)\n\nInstead of passing log messages to `console.log` they can be passed to\na supplied function.\n\nIf `write` is set to a single function, all logging objects are passed\nto this function.\n\n```js\nconst pino = require('pino')({\n  browser: {\n    write: (o) => {\n      // do something with o\n    }\n  }\n})\n```\n\nIf `write` is an object, it can have methods that correspond to the\nlevels. When a message is logged at a given level, the corresponding\nmethod is called. If a method isn't present, the logging falls back\nto using the `console`.\n\n\n```js\nconst pino = require('pino')({\n  browser: {\n    write: {\n      info: function (o) {\n        //process info log object\n      },\n      error: function (o) {\n        //process error log object\n      }\n    }\n  }\n})\n```\n\n### `serialize`: (Boolean | Array)\n\nThe serializers provided to `pino` are ignored by default in the browser, including\nthe standard serializers provided with Pino. Since the default destination for log\nmessages is the console, values such as `Error` objects are enhanced for inspection,\nwhich they otherwise wouldn't be if the Error serializer was enabled.\n\nWe can turn all serializers on,\n\n```js\nconst pino = require('pino')({\n  browser: {\n    serialize: true\n  }\n})\n```\n\nOr we can selectively enable them via an array:\n\n```js\nconst pino = require('pino')({\n  serializers: {\n    custom: myCustomSerializer,\n    another: anotherSerializer\n  },\n  browser: {\n    serialize: ['custom']\n  }\n})\n// following will apply myCustomSerializer to the custom property,\n// but will not apply anotherSerializer to another key\npino.info({custom: 'a', another: 'b'})\n```\n\nWhen `serialize` is `true` the standard error serializer is also enabled (see https://github.com/pinojs/pino/blob/master/docs/api.md#stdSerializers).\nThis is a global serializer, which will apply to any `Error` objects passed to the logger methods.\n\nIf `serialize` is an array the standard error serializer is also automatically enabled, it can\nbe explicitly disabled by including a string in the serialize array: `!stdSerializers.err`, like so:\n\n```js\nconst pino = require('pino')({\n  serializers: {\n    custom: myCustomSerializer,\n    another: anotherSerializer\n  },\n  browser: {\n    serialize: ['!stdSerializers.err', 'custom'] //will not serialize Errors, will serialize `custom` keys\n  }\n})\n```\n\nThe `serialize` array also applies to any child logger serializers (see https://github.com/pinojs/pino/blob/master/docs/api.md#discussion-2\nfor how to set child-bound serializers).\n\nUnlike server pino the serializers apply to every object passed to the logger method,\nif the `asObject` option is `true`, this results in the serializers applying to the\nfirst object (as in server pino).\n\nFor more info on serializers see https://github.com/pinojs/pino/blob/master/docs/api.md#mergingobject.\n\n### `transmit` (Object)\n\nAn object with `send` and `level` properties.\n\nThe `transmit.level` property specifies the minimum level (inclusive) of when the `send` function\nshould be called, if not supplied the `send` function be called based on the main logging `level`\n(set via `options.level`, defaulting to `info`).\n\nThe `transmit` object must have a `send` function which will be called after\nwriting the log message. The `send` function is passed the level of the log\nmessage and a `logEvent` object.\n\nThe `logEvent` object is a data structure representing a log message, it represents\nthe arguments passed to a logger statement, the level\nat which they were logged, and the hierarchy of child bindings.\n\nThe `logEvent` format is structured like so:\n\n```js\n{\n  ts = Number,\n  messages = Array,\n  bindings = Array,\n  level: { label = String, value = Number}\n}\n```\n\nThe `ts` property is a Unix epoch timestamp in milliseconds, the time is taken from the moment the\nlogger method is called.\n\nThe `messages` array is all arguments passed to logger method, (for instance `logger.info('a', 'b', 'c')`\nwould result in `messages` array `['a', 'b', 'c']`).\n\nThe `bindings` array represents each child logger (if any), and the relevant bindings.\nFor instance, given `logger.child({a: 1}).child({b: 2}).info({c: 3})`, the bindings array\nwould hold `[{a: 1}, {b: 2}]` and the `messages` array would be `[{c: 3}]`. The `bindings`\nare ordered according to their position in the child logger hierarchy, with the lowest index\nbeing the top of the hierarchy.\n\nBy default, serializers are not applied to log output in the browser, but they will *always* be\napplied to `messages` and `bindings` in the `logEvent` object. This allows us to ensure a consistent\nformat for all values between server and client.\n\nThe `level` holds the label (for instance `info`), and the corresponding numerical value\n(for instance `30`). This could be important in cases where client-side level values and\nlabels differ from server-side.\n\nThe point of the `send` function is to remotely record log messages:\n\n```js\nconst pino = require('pino')({\n  browser: {\n    transmit: {\n      level: 'warn',\n      send: function (level, logEvent) {\n        if (level === 'warn') {\n          // maybe send the logEvent to a separate endpoint\n          // or maybe analyze the messages further before sending\n        }\n        // we could also use the `logEvent.level.value` property to determine\n        // numerical value\n        if (logEvent.level.value >= 50) { // covers error and fatal\n\n          // send the logEvent somewhere\n        }\n      }\n    }\n  }\n})\n```\n\n### `disabled` (Boolean)\n\n```js\nconst pino = require('pino')({browser: {disabled: true}})\n```\n\nThe `disabled` option will disable logging in browser if set\nto `true`, by default it is set to `false`.\n"
  },
  {
    "path": "docs/bundling.md",
    "content": "# Bundling\n\nDue to its internal architecture based on Worker Threads, it is not possible to bundle Pino *without* generating additional files.\n\nIn particular, a bundler must ensure that the following files are also bundled separately:\n\n* `lib/worker.js` from the `thread-stream` dependency\n* `file.js`\n* `lib/worker.js`\n* Any transport used by the user (like `pino-pretty`)\n\nOnce the files above have been generated, the bundler must also add information about the files above by injecting a code that sets `__bundlerPathsOverrides` in the `globalThis` object.\n\nThe variable is an object whose keys are an identifier for the files and the values are the paths of files relative to the currently bundle files.\n\nExample:\n\n```javascript\n// Inject this using your bundle plugin\nglobalThis.__bundlerPathsOverrides = {\n  'thread-stream-worker': pinoWebpackAbsolutePath('./thread-stream-worker.js')\n  'pino/file': pinoWebpackAbsolutePath('./pino-file.js'),\n  'pino-worker': pinoWebpackAbsolutePath('./pino-worker.js'),\n  'pino-pretty': pinoWebpackAbsolutePath('./pino-pretty.js'),\n};\n```\n\nNote that `pino/file`, `pino-worker` and `thread-stream-worker` are required identifiers. Other identifiers are possible based on the user configuration.\n\n## Webpack Plugin\n\nIf you are a Webpack user, you can achieve this with [pino-webpack-plugin](https://github.com/pinojs/pino-webpack-plugin) without manual configuration of `__bundlerPathsOverrides`; however, you still need to configure it manually if you are using other bundlers.\n\n## Esbuild Plugin\n\n[esbuild-plugin-pino](https://github.com/davipon/esbuild-plugin-pino) is the esbuild plugin to generate extra pino files for bundling.\n\n## Bun Plugin\n\n[bun-plugin-pino](https://github.com/vktrl/bun-plugin-pino) is the Bun plugin to generate extra pino files for bundling."
  },
  {
    "path": "docs/child-loggers.md",
    "content": "# Child loggers\n\nLet's assume we want to have `\"module\":\"foo\"` added to every log within a\nmodule `foo.js`.\n\nTo accomplish this, simply use a child logger:\n\n```js\n'use strict'\n// imports a pino logger instance of `require('pino')()`\nconst parentLogger = require('./lib/logger')\nconst log = parentLogger.child({module: 'foo'})\n\nfunction doSomething () {\n  log.info('doSomething invoked')\n}\n\nmodule.exports = {\n  doSomething\n}\n```\n\n## Cost of child logging\n\nChild logger creation is fast:\n\n```\nbenchBunyanCreation*10000: 564.514ms\nbenchBoleCreation*10000: 283.276ms\nbenchPinoCreation*10000: 258.745ms\nbenchPinoExtremeCreation*10000: 150.506ms\n```\n\nLogging through a child logger has little performance penalty:\n\n```\nbenchBunyanChild*10000: 556.275ms\nbenchBoleChild*10000: 288.124ms\nbenchPinoChild*10000: 231.695ms\nbenchPinoExtremeChild*10000: 122.117ms\n```\n\nLogging via the child logger of a child logger also has negligible overhead:\n\n```\nbenchBunyanChildChild*10000: 559.082ms\nbenchPinoChildChild*10000: 229.264ms\nbenchPinoExtremeChildChild*10000: 127.753ms\n```\n\n## Duplicate keys caveat\n\nNaming conflicts can arise between child loggers and\nchildren of child loggers.\n\nThis isn't as bad as it sounds, even if the same keys between\nparent and child loggers are used, Pino resolves the conflict in the sanest way.\n\nFor example, consider the following:\n\n```js\nconst pino = require('pino')\npino(pino.destination('./my-log'))\n  .child({a: 'property'})\n  .child({a: 'prop'})\n  .info('howdy')\n```\n\n```sh\n$ cat my-log\n{\"pid\":95469,\"hostname\":\"MacBook-Pro-3.home\",\"level\":30,\"msg\":\"howdy\",\"time\":1459534114473,\"a\":\"property\",\"a\":\"prop\"}\n```\n\nNotice how there are two keys named `a` in the JSON output. The sub-child's properties\nappear after the parent child properties.\n\nAt some point, the logs will most likely be processed (for instance with a [transport](transports.md)),\nand this generally involves parsing. `JSON.parse` will return an object where the conflicting\nnamespace holds the final value assigned to it:\n\n```sh\n$ cat my-log | node -e \"process.stdin.once('data', (line) => console.log(JSON.stringify(JSON.parse(line))))\"\n{\"pid\":95469,\"hostname\":\"MacBook-Pro-3.home\",\"level\":30,\"msg\":\"howdy\",\"time\":\"2016-04-01T18:08:34.473Z\",\"a\":\"prop\"}\n```\n\nUltimately the conflict is resolved by taking the last value, which aligns with Bunyan's child logging\nbehavior.\n\nThere may be cases where this edge case becomes problematic if a JSON parser with alternative behavior\nis used to process the logs. It's recommended to be conscious of namespace conflicts with child loggers,\nin light of an expected log processing approach.\n\nOne of Pino's performance tricks is to avoid building objects and stringifying\nthem, so we're building strings instead. This is why duplicate keys between\nparents and children will end up in the log output.\n"
  },
  {
    "path": "docs/diagnostics.md",
    "content": "# Diagnostics\n\nPino provides [tracing channel](tc) events that allow insight into the\ninternal workings of the library. The currently supported events are:\n\n+ `tracing:pino_asJson:start`: emitted when the final serialization process\n  of logs is started. The emitted event payload has the following fields:\n  - `instance`: the Pino instance associated with the function\n  - `arguments`: the arguments passed to the function\n+ `tracing:pino_asJson:end`: emitted at the end of the final serialization\n  process. The emitted event payload has the following fields:\n  - `instance`: the Pino instance associated with the function\n  - `arguments`: the arguments passed to the function\n  - `result`: the finalized, newline delimited, log line as a string\n\n[tc]: https://nodejs.org/docs/latest/api/diagnostics_channel.html#tracingchannel-channels\n"
  },
  {
    "path": "docs/ecosystem.md",
    "content": "# Pino Ecosystem\n\nThis is a list of ecosystem modules that integrate with `pino`.\n\nModules listed under [Core](#core) are maintained by the Pino team. Modules\nlisted under [Community](#community) are maintained by independent community\nmembers.\n\nPlease send a PR to add new modules!\n\n<a id=\"core\"></a>\n## Core\n\n### Frameworks\n+ [`express-pino-logger`](https://github.com/pinojs/express-pino-logger): use\nPino to log requests within [express](https://expressjs.com/).\n+ [`koa-pino-logger`](https://github.com/pinojs/koa-pino-logger): use Pino to\nlog requests within [Koa](https://koajs.com/).\n+ [`restify-pino-logger`](https://github.com/pinojs/restify-pino-logger): use\nPino to log requests within [restify](http://restify.com/).\n+ [`rill-pino-logger`](https://github.com/pinojs/rill-pino-logger): use Pino as\nthe logger for the [Rill framework](https://rill.site/).\n\n### Utilities\n+ [`pino-arborsculpture`](https://github.com/pinojs/pino-arborsculpture): change\nlog levels at runtime.\n+ [`pino-caller`](https://github.com/pinojs/pino-caller): add callsite to the log line.\n+ [`pino-clf`](https://github.com/pinojs/pino-clf): reformat Pino logs into\nCommon Log Format.\n+ [`pino-console`](https://github.com/pinojs/pino-console): adapter for the [WHATWG Console](https://console.spec.whatwg.org/) spec. \n+ [`pino-debug`](https://github.com/pinojs/pino-debug): use Pino to interpret\n[`debug`](https://npm.im/debug) logs.\n+ [`pino-elasticsearch`](https://github.com/pinojs/pino-elasticsearch): send\nPino logs to an Elasticsearch instance.\n+ [`pino-eventhub`](https://github.com/pinojs/pino-eventhub): send Pino logs\nto an [Event Hub](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-what-is-event-hubs).\n+ [`pino-filter`](https://github.com/pinojs/pino-filter): filter Pino logs in\nthe same fashion as the [`debug`](https://npm.im/debug) module.\n+ [`pino-gelf`](https://github.com/pinojs/pino-gelf): reformat Pino logs into\nGELF format for Graylog.\n+ [`pino-hapi`](https://github.com/pinojs/hapi-pino): use Pino as the logger\nfor [Hapi](https://hapijs.com/).\n+ [`pino-http`](https://github.com/pinojs/pino-http): easily use Pino to log\nrequests with the core `http` module.\n+ [`pino-http-print`](https://github.com/pinojs/pino-http-print): reformat Pino\nlogs into traditional [HTTPD](https://httpd.apache.org/) style request logs.\n+ [`pino-mongodb`](https://github.com/pinojs/pino-mongodb): store Pino logs\nin a MongoDB database.\n+ [`pino-multi-stream`](https://github.com/pinojs/pino-multi-stream): send\nlogs to multiple destination streams (slow!).\n+ [`pino-noir`](https://github.com/pinojs/pino-noir): redact sensitive information\nin logs.\n+ [`pino-pretty`](https://github.com/pinojs/pino-pretty): basic prettifier to\nmake log lines human-readable.\n+ [`pino-socket`](https://github.com/pinojs/pino-socket): send logs to TCP or UDP\ndestinations.\n+ [`pino-std-serializers`](https://github.com/pinojs/pino-std-serializers): the\ncore object serializers used within Pino.\n+ [`pino-syslog`](https://github.com/pinojs/pino-syslog): reformat Pino logs\nto standard syslog format.\n+ [`pino-tee`](https://github.com/pinojs/pino-tee): pipe Pino logs into files\nbased upon log levels.\n+ [`pino-test`](https://github.com/pinojs/pino-test): a set of utilities for \nverifying logs generated by the Pino logger.\n+ [`pino-toke`](https://github.com/pinojs/pino-toke): reformat Pino logs\naccording to a given format string.\n\n\n<a id=\"community\"></a>\n## Community\n\n+ [`@google-cloud/pino-logging-gcp-config`](https://www.npmjs.com/package/@google-cloud/pino-logging-gcp-config): Config helper and formatter to output [Google Cloud Platform Structured Logging](https://cloud.google.com/logging/docs/structured-logging)\n+ [`@newrelic/pino-enricher`](https://github.com/newrelic/newrelic-node-log-extensions/blob/main/packages/pino-log-enricher): a log customization to add New Relic context to use [Logs In Context](https://docs.newrelic.com/docs/logs/logs-context/logs-in-context/)\n+ [`@sentry/node`](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/pino/): Sentry SDK with native pinoIntegration for direct Pino instrumentation and error tracking.\n+ [`cloud-pine`](https://github.com/metcoder95/cloud-pine): transport that provides abstraction and compatibility with [`@google-cloud/logging`](https://www.npmjs.com/package/@google-cloud/logging).\n+ [`cls-proxify`](https://github.com/keenondrums/cls-proxify): integration of pino and [CLS](https://github.com/jeff-lewis/cls-hooked). Useful for creating dynamically configured child loggers (e.g. with added trace ID) for each request.\n+ [`crawlee-pino`](https://github.com/imyelo/crawlee-pino): use Pino to log within Crawlee\n+ [`eslint-plugin-pino`](https://github.com/orzarchi/eslint-plugin-pino): linting rules for pino usage, primarly for preventing missing context in logs due to incorrect argument order.\n+ [`pino-colada`](https://github.com/lrlna/pino-colada): cute ndjson formatter for pino.\n+ [`pino-dev`](https://github.com/dnjstrom/pino-dev): simple prettifier for pino with built-in support for common ecosystem packages.\n+ [`pino-fluentd`](https://github.com/davidedantonio/pino-fluentd): send Pino logs to Elasticsearch,\nMongoDB, and many [others](https://www.fluentd.org/dataoutputs) via Fluentd.\n+ [`pino-lambda`](https://github.com/FormidableLabs/pino-lambda): log transport for cloudwatch support inside aws-lambda \n+ [`pino-pretty-min`](https://github.com/unjello/pino-pretty-min): a minimal\nprettifier inspired by the [logrus](https://github.com/sirupsen/logrus) logger.\n+ [`pino-rotating-file`](https://github.com/homeaway/pino-rotating-file): a hapi-pino log transport for splitting logs into separate, automatically rotating files.\n+ [`pino-tiny`](https://github.com/holmok/pino-tiny): a tiny (and extensible?) little log formatter for pino.\n"
  },
  {
    "path": "docs/help.md",
    "content": "# Help\n\n* [Log rotation](#rotate)\n* [Reopening log files](#reopening)\n* [Saving to multiple files](#multiple)\n* [Log filtering](#filter-logs)\n* [Transports and systemd](#transport-systemd)\n* [Log to different streams](#multi-stream)\n* [Duplicate keys](#dupe-keys)\n* [Log levels as labels instead of numbers](#level-string)\n* [Pino with `debug`](#debug)\n* [Unicode and Windows terminal](#windows)\n* [Mapping Pino Log Levels to Google Cloud Logging (Stackdriver) Severity Levels](#stackdriver)\n* [Using Grafana Loki to evaluate pino logs in a kubernetes cluster](#grafana-loki)\n* [Avoid Message Conflict](#avoid-message-conflict)\n* [Best performance for logging to `stdout`](#best-performance-for-stdout)\n* [Testing](#testing)\n\n<a id=\"rotate\"></a>\n## Log rotation\n\nUse a separate tool for log rotation:\nWe recommend [logrotate](https://github.com/logrotate/logrotate).\nConsider we output our logs to `/var/log/myapp.log` like so:\n\n```\n$ node server.js > /var/log/myapp.log\n```\n\nWe would rotate our log files with logrotate, by adding the following to `/etc/logrotate.d/myapp`:\n\n```\n/var/log/myapp.log {\n       su root\n       daily\n       rotate 7\n       delaycompress\n       compress\n       notifempty\n       missingok\n       copytruncate\n}\n```\n\nThe `copytruncate` configuration has a very slight possibility of lost log lines due\nto a gap between copying and truncating - the truncate may occur after additional lines\nhave been written. To perform log rotation without `copytruncate`, see the [Reopening log files](#reopening)\nhelp.\n\n<a id=\"reopening\"></a>\n## Reopening log files\n\nIn cases where a log rotation tool doesn't offer copy-truncate capabilities,\nor where using them is deemed inappropriate, `pino.destination`\ncan reopen file paths after a file has been moved away.\n\nOne way to use this is to set up a `SIGUSR2` or `SIGHUP` signal handler that\nreopens the log file destination, making sure to write the process PID out\nsomewhere so the log rotation tool knows where to send the signal.\n\n```js\n// write the process pid to a well known location for later\nconst fs = require('node:fs')\nfs.writeFileSync('/var/run/myapp.pid', process.pid)\n\nconst dest = pino.destination('/log/file')\nconst logger = require('pino')(dest)\nprocess.on('SIGHUP', () => dest.reopen())\n```\n\nThe log rotation tool can then be configured to send this signal to the process\nafter a log rotation event has occurred.\n\nGiven a similar scenario as in the [Log rotation](#rotate) section a basic\n`logrotate` config that aligns with this strategy would look similar to the following:\n\n```\n/var/log/myapp.log {\n       su root\n       daily\n       rotate 7\n       delaycompress\n       compress\n       notifempty\n       missingok\n       postrotate\n           kill -HUP `cat /var/run/myapp.pid`\n       endscript\n}\n```\n\n<a id=\"multiple\"></a>\n## Saving to multiple files\n\nSee [`pino.multistream`](/docs/api.md#pino-multistream).\n\n<a id=\"filter-logs\"></a>\n## Log Filtering\nThe Pino philosophy advocates common, preexisting, system utilities.\n\nSome recommendations in line with this philosophy are:\n\n1. Use [`grep`](https://linux.die.net/man/1/grep):\n    ```sh\n    $ # View all \"INFO\" level logs\n    $ node app.js | grep '\"level\":30'\n    ```\n1. Use [`jq`](https://stedolan.github.io/jq/):\n    ```sh\n    $ # View all \"ERROR\" level logs\n    $ node app.js | jq 'select(.level == 50)'\n    ```\n\n<a id=\"transport-systemd\"></a>\n## Transports and systemd\n`systemd` makes it complicated to use pipes in services. One method for overcoming\nthis challenge is to use a subshell:\n\n```\nExecStart=/bin/sh -c '/path/to/node app.js | pino-transport'\n```\n\n<a id=\"multi-stream\"></a>\n## Log to different streams\n\nPino's default log destination is the singular destination of `stdout`. While\nnot recommended for performance reasons, multiple destinations can be targeted\nby using [`pino.multistream`](/docs/api.md#pino-multistream).\n\nIn this example, we use `stderr` for `error` level logs and `stdout` as default\nfor all other levels (e.g. `debug`, `info`, and `warn`).\n\n```js\nconst pino = require('pino')\nvar streams = [\n  {level: 'debug', stream: process.stdout},\n  {level: 'error', stream: process.stderr},\n  {level: 'fatal', stream: process.stderr}\n]\n\nconst logger = pino({\n  name: 'my-app',\n  level: 'debug', // must be the lowest level of all streams\n}, pino.multistream(streams))\n```\n\n<a id=\"dupe-keys\"></a>\n## How Pino handles duplicate keys\n\nDuplicate keys are possibly when a child logger logs an object with a key that\ncollides with a key in the child loggers bindings.\n\nSee the [child logger duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat)\nfor information on this is handled.\n\n<a id=\"level-string\"></a>\n## Log levels as labels instead of numbers\nPino log lines are meant to be parsable. Thus, Pino's default mode of operation\nis to print the level value instead of the string name. \nHowever, you can use the [`formatters`](/docs/api.md#formatters-object) option \nwith a [`level`](/docs/api.md#level) function to print the string name instead of the level value :\n\n```js\nconst pino = require('pino')\n\nconst log = pino({\n  formatters: {\n    level: (label) => {\n      return {\n        level: label\n      }\n    }\n  }\n})\n\nlog.info('message')\n\n// {\"level\":\"info\",\"time\":1661632832200,\"pid\":18188,\"hostname\":\"foo\",\"msg\":\"message\"}\n```\n\nAlthough it works, we recommend using one of these options instead if you are able:\n\n1. If the only change desired is the name then a transport can be used. One such\ntransport is [`pino-text-level-transport`](https://npm.im/pino-text-level-transport).\n1. Use a prettifier like [`pino-pretty`](https://npm.im/pino-pretty) to make\nthe logs human friendly.\n\n<a id=\"debug\"></a>\n## Pino with `debug`\n\nThe popular [`debug`](https://npm.im/debug) is used in many modules across the ecosystem.\n\nThe [`pino-debug`](https://github.com/pinojs/pino-debug) module\ncan capture calls to `debug` loggers and run them\nthrough `pino` instead. This results in a 10x (20x in asynchronous mode)\nperformance improvement - even though `pino-debug` is logging additional\ndata and wrapping it in JSON.\n\nTo quickly enable this install [`pino-debug`](https://github.com/pinojs/pino-debug)\nand preload it with the `-r` flag, enabling any `debug` logs with the\n`DEBUG` environment variable:\n\n```sh\n$ npm i pino-debug\n$ DEBUG=* node -r pino-debug app.js\n```\n\n[`pino-debug`](https://github.com/pinojs/pino-debug) also offers fine-grain control to map specific `debug`\nnamespaces to `pino` log levels. See [`pino-debug`](https://github.com/pinojs/pino-debug)\nfor more.\n\n<a id=\"windows\"></a>\n## Unicode and Windows terminal\n\nPino uses [sonic-boom](https://github.com/mcollina/sonic-boom) to speed\nup logging. Internally, it uses [`fs.write`](https://nodejs.org/dist/latest-v10.x/docs/api/fs.html#fs_fs_write_fd_string_position_encoding_callback) to write log lines directly to a file\ndescriptor. On Windows, Unicode output is not handled properly in the\nterminal (both `cmd.exe` and PowerShell), and as such the output could\nbe visualized incorrectly if the log lines include utf8 characters. It\nis possible to configure the terminal to visualize those characters\ncorrectly with the use of [`chcp`](https://ss64.com/nt/chcp.html) by\nexecuting in the terminal `chcp 65001`. This is a known limitation of\nNode.js.\n\n<a id=\"stackdriver\"></a>\n## Mapping Pino Log Levels to Google Cloud Logging (Stackdriver) Severity Levels\n\nGoogle Cloud Logging uses `severity` levels instead of log levels. As a result, all logs may show as INFO\nlevel logs while completely ignoring the level set in the pino log. Google Cloud Logging also prefers that\nlog data is present inside a `message` key instead of the default `msg` key that Pino uses. Use a technique\nsimilar to the one below to retain log levels in Google Cloud Logging\n\n```js\nconst pino = require('pino')\n\n// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity\nconst PinoLevelToSeverityLookup = {\n  trace: 'DEBUG',\n  debug: 'DEBUG',\n  info: 'INFO',\n  warn: 'WARNING',\n  error: 'ERROR',\n  fatal: 'CRITICAL',\n};\n\nconst defaultPinoConf = {\n  messageKey: 'message',\n  formatters: {\n    level(label, number) {\n      return {\n        severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup['info'],\n        level: number,\n      }\n    }\n  },\n}\n\nmodule.exports = function createLogger(options) {\n  return pino(Object.assign({}, options, defaultPinoConf))\n}\n```\n\nA library that configures Pino for\n[Google Cloud Structured Logging](https://cloud.google.com/logging/docs/structured-logging)\nis available at:\n[@google-cloud/pino-logging-gcp-config](https://www.npmjs.com/package/@google-cloud/pino-logging-gcp-config)\n\nThis library has the following features:\n\n+ Converts Pino log levels to Google Cloud Logging log levels, as above\n+ Uses `message` instead of `msg` for the message key, as above\n+ Adds a millisecond-granularity timestamp in the \n  [structure](https://cloud.google.com/logging/docs/agent/logging/configuration#timestamp-processing)\n  recognised by Google Cloud Logging eg: \\\n  `\"timestamp\":{\"seconds\":1445470140,\"nanos\":123000000}`\n+ Adds a sequential\n  [`insertId`](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#FIELDS.insert_id)\n  to ensure log messages with identical timestamps are ordered correctly.\n+ Logs including an `Error` object have the\n  [`stack_trace`](https://cloud.google.com/error-reporting/docs/formatting-error-messages#log-error)\n  property set so that the error is forwarded to Google Cloud Error Reporting.\n+ Includes a\n  [`ServiceContext`](https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext)\n  object in the logs for Google Cloud Error Reporting, auto detected from the\n  environment if not specified\n+ Maps the OpenTelemetry properties `span_id`, `trace_id`, and `trace_flags`\n  to the equivalent Google Cloud Logging fields.\n\n<a id=\"grafana-loki\"></a>\n## Using Grafana Loki to evaluate pino logs in a kubernetes cluster\n\nTo get pino logs into Grafana Loki there are two options:\n\n1. **Push:** Use [pino-loki](https://github.com/Julien-R44/pino-loki) to send logs directly to Loki.\n1. **Pull:** Configure Grafana Promtail to read and properly parse the logs before sending them to Loki.  \n   Similar to Google Cloud logging, this involves remapping the log levels. See this [article](https://medium.com/@janpaepke/structured-logging-in-the-grafana-monitoring-stack-8aff0a5af2f5) for details.\n\n<a id=\"avoid-message-conflict\"></a>\n## Avoid Message Conflict\n\nAs described in the [`message` documentation](/docs/api.md#message), when a log\nis written like `log.info({ msg: 'a message' }, 'another message')` then the\nfinal output JSON will have `\"msg\":\"another message\"` and the `'a message'`\nstring will be lost. To overcome this, the [`logMethod` hook](/docs/api.md#logmethod)\ncan be used:\n\n```js\n'use strict'\n\nconst log = require('pino')({\n  level: 'debug',\n  hooks: {\n    logMethod (inputArgs, method) {\n      if (inputArgs.length === 2 && inputArgs[0].msg) {\n       inputArgs[0].originalMsg = inputArgs[0].msg\n      }\n      return method.apply(this, inputArgs)\n    }\n  }\n})\n\nlog.info('no original message')\nlog.info({ msg: 'mapped to originalMsg' }, 'a message')\n\n// {\"level\":30,\"time\":1596313323106,\"pid\":63739,\"hostname\":\"foo\",\"msg\":\"no original message\"}\n// {\"level\":30,\"time\":1596313323107,\"pid\":63739,\"hostname\":\"foo\",\"msg\":\"a message\",\"originalMsg\":\"mapped to originalMsg\"}\n```\n\n<a id=\"best-performance-for-stdout\"></a>\n## Best performance for logging to `stdout`\n\nThe best performance for logging directly to stdout is _usually_ achieved by using the\ndefault configuration:\n\n```js\nconst log = require('pino')();\n```\n\nYou should only have to configure custom transports or other settings\nif you have broader logging requirements.\n\n<a id=\"testing\"></a>\n## Testing\n\nSee [`pino-test`](https://github.com/pinojs/pino-test).\n"
  },
  {
    "path": "docs/lts.md",
    "content": "## Long Term Support\n\nPino's Long Term Support (LTS) is provided according to the schedule laid\nout in this document:\n\n1. Major releases, \"X\" release of [semantic versioning][semver] X.Y.Z release\n   versions, are supported for a minimum period of six months from their release\n   date. The release date of any specific version can be found at\n   [https://github.com/pinojs/pino/releases](https://github.com/pinojs/pino/releases).\n\n1. Major releases will receive security updates for an additional six months\n   from the release of the next major release. After this period\n   we will still review and release security fixes as long as they are\n   provided by the community and they do not violate other constraints,\n   e.g. minimum supported Node.js version.\n\n1. Major releases will be tested and verified against all Node.js\n   release lines that are supported by the\n   [Node.js LTS policy](https://github.com/nodejs/Release) within the\n   LTS period of that given Pino release line. This implies that only\n   the latest Node.js release of a given line is supported.\n\nA \"month\" is defined as 30 consecutive days.\n\n> ## Security Releases and Semver\n>\n> As a consequence of providing long-term support for major releases, there\n> are occasions where we need to release breaking changes as a _minor_\n> version release. Such changes will _always_ be noted in the\n> [release notes](https://github.com/pinojs/pino/releases).\n>\n> To avoid automatically receiving breaking security updates it is possible to use\n> the tilde (`~`) range qualifier. For example, to get patches for the 6.1\n> release, and avoid automatically updating to the 6.1 release, specify\n> the dependency as `\"pino\": \"~6.1.x\"`. This will leave your application vulnerable,\n> so please use with caution.\n\n[semver]: https://semver.org/\n\n<a name=\"lts-schedule\"></a>\n\n### Schedule\n\n| Version | Release Date | End Of LTS Date | Node.js              |\n| :------ | :----------- | :-------------- | :------------------- |\n| 9.x     | 2024-04-26   | TBD             | 18, 20, 22            |\n| 8.x     | 2022-06-01   | 2024-10-26      | 14, 16, 18, 20        |\n| 7.x     | 2021-10-14   | 2023-06-01      | 12, 14, 16           |\n| 6.x     | 2020-03-07   | 2022-04-14      | 10, 12, 14, 16       |\n\n<a name=\"supported-os\"></a>\n\n### CI tested operating systems\n\nPino uses GitHub Actions for CI testing, please refer to\n[GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)\nfor further details on what the latest virtual environment is in relation to\nthe YAML workflow labels below:\n\n| OS      | YAML Workflow Label    | Node.js      |\n|---------|------------------------|--------------|\n| Linux   | `ubuntu-latest`        | 18, 20, 22   |\n| Windows | `windows-latest`       | 18, 20, 22   |\n| MacOS   | `macos-latest`         | 18, 20, 22   |\n"
  },
  {
    "path": "docs/pretty.md",
    "content": "# Pretty Printing\n\nBy default, Pino log lines are newline delimited JSON (NDJSON). This is perfect\nfor production usage and long-term storage. It's not so great for development\nenvironments. Thus, Pino logs can be prettified by using a Pino prettifier\nmodule like [`pino-pretty`][pp]:\n\n1. Install a prettifier module as a separate dependency, e.g. `npm install pino-pretty`.\n2. Instantiate the logger with the `transport.target` option set to `'pino-pretty'`:\n  ```js\n  const pino = require('pino')\n  const logger = pino({\n    transport: {\n      target: 'pino-pretty'\n    },\n  })\n\n  logger.info('hi')\n  ```\n3. The transport option can also have an options object containing `pino-pretty` options:\n  ```js\n  const pino = require('pino')\n  const logger = pino({\n    transport: {\n      target: 'pino-pretty',\n      options: {\n        colorize: true\n      }\n    }\n  })\n\n  logger.info('hi')\n  ```\n\n**Note:** The `logger.flush()` method does not work when using `pino-pretty`. See\n[Flush Limitations with `pino-pretty`](/docs/asynchronous.md) for more details.\n\n  [pp]: https://github.com/pinojs/pino-pretty\n"
  },
  {
    "path": "docs/redaction.md",
    "content": "# Redaction\n\nTo redact sensitive information, supply paths to keys that hold sensitive data\nusing the `redact` option. Note that paths that contain hyphens need to use\nbrackets to access the hyphenated property:\n\n```js\nconst logger = require('.')({\\n  redact: ['key', 'path.to.key', 'stuff.thats[*].secret', 'path[\"with-hyphen\"]']\n})\n\nlogger.info({\n  key: 'will be redacted',\n  path: {\n    to: {key: 'sensitive', another: 'thing'}\n  },\n  stuff: {\n    thats: [\n      {secret: 'will be redacted', logme: 'will be logged'},\n      {secret: 'as will this', logme: 'as will this'}\n    ]\n  }\n})\n```\n\nThis will output:\n\n```JSON\n{\"level\":30,\"time\":1527777350011,\"pid\":3186,\"hostname\":\"Davids-MacBook-Pro-3.local\",\"key\":\"[Redacted]\",\"path\":{\"to\":{\"key\":\"[Redacted]\",\"another\":\"thing\"}},\"stuff\":{\"thats\":[{\"secret\":\"[Redacted]\",\"logme\":\"will be logged\"},{\"secret\":\"[Redacted]\",\"logme\":\"as will this\"}]}}\n```\n\nThe `redact` option can take an array (as shown in the above example) or\nan object. This allows control over *how* information is redacted.\n\nFor instance, setting the censor:\n\n```js\nconst logger = require('.')({\\n  redact: {\n    paths: ['key', 'path.to.key', 'stuff.thats[*].secret'],\n    censor: '**GDPR COMPLIANT**'\n  }\n})\n\nlogger.info({\n  key: 'will be redacted',\n  path: {\n    to: {key: 'sensitive', another: 'thing'}\n  },\n  stuff: {\n    thats: [\n      {secret: 'will be redacted', logme: 'will be logged'},\n      {secret: 'as will this', logme: 'as will this'}\n    ]\n  }\n})\n```\n\nThis will output:\n\n```JSON\n{\"level\":30,\"time\":1527778563934,\"pid\":3847,\"hostname\":\"Davids-MacBook-Pro-3.local\",\"key\":\"**GDPR COMPLIANT**\",\"path\":{\"to\":{\"key\":\"**GDPR COMPLIANT**\",\"another\":\"thing\"}},\"stuff\":{\"thats\":[{\"secret\":\"**GDPR COMPLIANT**\",\"logme\":\"will be logged\"},{\"secret\":\"**GDPR COMPLIANT**\",\"logme\":\"as will this\"}]}}\n```\n\nThe `redact.remove` option also allows for the key and value to be removed from output:\n\n```js\nconst logger = require('.')({\\n  redact: {\n    paths: ['key', 'path.to.key', 'stuff.thats[*].secret'],\n    remove: true\n  }\n})\n\nlogger.info({\n  key: 'will be redacted',\n  path: {\n    to: {key: 'sensitive', another: 'thing'}\n  },\n  stuff: {\n    thats: [\n      {secret: 'will be redacted', logme: 'will be logged'},\n      {secret: 'as will this', logme: 'as will this'}\n    ]\n  }\n})\n```\n\nThis will output\n\n```JSON\n{\"level\":30,\"time\":1527782356751,\"pid\":5758,\"hostname\":\"Davids-MacBook-Pro-3.local\",\"path\":{\"to\":{\"another\":\"thing\"}},\"stuff\":{\"thats\":[{\"logme\":\"will be logged\"},{\"logme\":\"as will this\"}]}}\n```\n\nSee [pino options in API](/docs/api.md#redact-array-object) for `redact` API details.\n\n<a name=\"paths\"></a>\n## Path Syntax\n\nThe syntax for paths supplied to the `redact` option conform to the syntax in path lookups\nin standard ECMAScript, with two additions:\n\n* paths may start with bracket notation\n* paths may contain the asterisk `*` to denote a wildcard\n* paths are **case sensitive**\n\nBy way of example, the following are all valid paths:\n\n* `a.b.c`\n* `a[\"b-c\"].d`\n* `[\"a-b\"].c`\n* `a.b.*`\n* `a[*].b`\n\n## Overhead\n\nPino's redaction functionality is built on top of [`fast-redact`](https://github.com/davidmarkclements/fast-redact)\nwhich adds about 2% overhead to `JSON.stringify` when using paths without wildcards.\n\nWhen used with pino logger with a single redacted path, any overhead is within noise -\na way to deterministically measure its effect has not been found. This is because it is not a bottleneck.\n\nHowever, wildcard redaction does carry a non-trivial cost relative to explicitly declaring the keys\n(50% in a case where four keys are redacted across two objects). See\nthe [`fast-redact` benchmarks](https://github.com/davidmarkclements/fast-redact#benchmarks) for details.\n\n## Safety\n\nThe `redact` option is intended as an initialization time configuration option.\nPath strings must not originate from user input.\nThe `fast-redact` module uses a VM context to syntax check the paths, user input\nshould never be combined with such an approach. See the [`fast-redact` Caveat](https://github.com/davidmarkclements/fast-redact#caveat)\nand the [`fast-redact` Approach](https://github.com/davidmarkclements/fast-redact#approach) for in-depth information.\n"
  },
  {
    "path": "docs/transports.md",
    "content": "# Transports\n\nPino transports can be used for both transmitting and transforming log output.\n\nThe way Pino generates logs:\n\n1. Reduces the impact of logging on an application to the absolute minimum.\n2. Gives greater flexibility in how logs are processed and stored.\n\nIt is recommended that any log transformation or transmission is performed either\nin a separate thread or a separate process.\n\nBefore Pino v7 transports would ideally operate in a separate process - these are\nnow referred to as [Legacy Transports](#legacy-transports).\n\nFrom Pino v7 and upwards transports can also operate inside a [Worker Thread][worker-thread]\nand can be used or configured via the options object passed to `pino` on initialization.\nIn this case the transports would always operate asynchronously (unless `options.sync` is set to `true` in transport options), and logs would be\nflushed as quickly as possible (there is nothing to do).\n\n[worker-thread]: https://nodejs.org/dist/latest-v14.x/docs/api/worker_threads.html\n\n## v7+ Transports\n\nA transport is a module that exports a default function that returns a writable stream:\n\n```js\nimport { createWriteStream } from 'node:fs'\n\nexport default (options) => {\n  return createWriteStream(options.destination)\n}\n```\n\nLet's imagine the above defines our \"transport\" as the file `my-transport.mjs`\n(ESM files are supported even if the project is written in CJS).\n\nWe would set up our transport by creating a transport stream with `pino.transport`\nand passing it to the `pino` function:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: '/absolute/path/to/my-transport.mjs'\n})\npino(transport)\n```\n\nThe transport code will be executed in a separate worker thread. The main thread\nwill write logs to the worker thread, which will write them to the stream returned\nfrom the function exported from the transport file/module.\n\nThe exported function can also be async. If we use an async function we can throw early\nif the transform could not be opened. As an example:\n\n```js\nimport fs from 'node:fs'\nimport { once } from 'events'\nexport default async (options) => {\n  const stream = fs.createWriteStream(options.destination)\n  await once(stream, 'open')\n  return stream\n}\n```\n\nWhile initializing the stream we're able to use `await` to perform asynchronous operations. In this\ncase, waiting for the write streams `open` event.\n\nLet's imagine the above was published to npm with the module name `some-file-transport`.\n\nThe `options.destination` value can be set when creating the transport stream with `pino.transport` like so:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'some-file-transport',\n  options: { destination: '/dev/null' }\n})\npino(transport)\n```\n\nNote here we've specified a module by package rather than by relative path. The options object we provide\nis serialized and injected into the transport worker thread, then passed to the module's exported function.\nThis means that the options object can only contain types that are supported by the\n[Structured Clone Algorithm][sca] which is used to (de)serialize objects between threads.\n\nWhat if we wanted to use both transports, but send only error logs to `my-transport.mjs` while\nsending all logs to `some-file-transport`? We can use the per-target `level` option:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [\n    { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n    { target: 'some-file-transport', options: { destination: '/dev/null' }}\n  ]\n})\npino(transport)\n```\n\n### How level filtering works with transports\n\nPino applies level filtering in two different places depending on the transport configuration.\n\n#### A) Single `target` (or single `pipeline`)\n\n```text\nMain thread                                   Worker thread\n────────────────────────────────────────────  ─────────────────────────────────\nlogger.debug()/info()/...                     transport target (stream)\n        │                                              ▲\n        ▼                                              │\nlogger.level gate (enabled methods) ──ThreadStream─────┘\n\nResult:\n- `logger.level` decides what is emitted.\n- `transport.level` is not used in this path.\n```\n\n#### B) `targets` (multiple destinations)\n\n```text\nMain thread                                   Worker thread\n────────────────────────────────────────────  ─────────────────────────────────\nlogger.debug()/info()/...                     pino.multistream\n        │                                      (per-target level filter)\n        ▼                                              │\nlogger.level gate (enabled methods) ──ThreadStream────┼──> target #1 (level: ...)\n                                                       ├──> target #2 (level: ...)\n                                                       └──> target #N (default: info)\n\nResult:\n- `logger.level` is the first gate.\n- each `targets[i].level` is the second gate.\n- missing `targets[i].level` defaults to `info`.\n```\n\nSummary:\n\n- Single `target`/single `pipeline`: only `logger.level` filters messages.\n- Multiple `targets`: `logger.level` is applied first, then each `targets[i].level` is applied.\n- If `targets[i].level` is missing, it defaults to `info`.\n\nIf you need `debug` (or lower) logs to reach one or more targets, set:\n\n1. `logger.level` low enough, and\n2. `level` on each target that should receive those messages.\n\nIf we're using custom levels, they should be passed in when using more than one transport.\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [\n    { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n    { target: 'some-file-transport', options: { destination: '/dev/null' }\n  ],\n  levels: { foo: 35 }\n})\npino(transport)\n```\n\nIt is also possible to use the `dedupe` option to send logs only to the stream with the higher level.\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [\n    { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n    { target: 'some-file-transport', options: { destination: '/dev/null' }\n  ],\n  dedupe: true\n})\npino(transport)\n```\n\nTo make pino log synchronously, pass `sync: true` to transport options.\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [\n    { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n  ],\n  dedupe: true,\n  sync: true,\n});\npino(transport);\n```\n\nFor more details on `pino.transport` see the [API docs for `pino.transport`][pino-transport].\n\n### Using transports with `--import` or `--require` preloads\n\nPino transports work correctly when loaded via Node.js preload flags (`--import` or `--require`).\nPino automatically detects when it's being loaded during the preload phase and filters out the\npreload flags from the transport worker's `execArgv` to prevent infinite worker spawning.\n\n```js\n// preload.mjs\nimport pino from 'pino'\n\nexport const logger = pino({\n  transport: {\n    target: 'pino-pretty'\n  }\n})\n```\n\n```bash\nnode --import=./preload.mjs app.js\n```\n\n[pino-transport]: /docs/api.md#pino-transport\n[sca]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm\n\n<a id=\"writing\"></a>\n### Writing a Transport\n\nThe module [pino-abstract-transport](https://github.com/pinojs/pino-abstract-transport) provides\na simple utility to parse each line.  Its usage is highly recommended.\n\nYou can see an example using an async iterator with ESM:\n\n```js\nimport build from 'pino-abstract-transport'\nimport SonicBoom from 'sonic-boom'\nimport { once } from 'events'\n\nexport default async function (opts) {\n  // SonicBoom is necessary to avoid loops with the main thread.\n  // It is the same of pino.destination().\n  const destination = new SonicBoom({ dest: opts.destination || 1, sync: false })\n  await once(destination, 'ready')\n\n  return build(async function (source) {\n    for await (let obj of source) {\n      const toDrain = !destination.write(obj.msg.toUpperCase() + '\\n')\n      // This block will handle backpressure\n      if (toDrain) {\n        await once(destination, 'drain')\n      }\n    }\n  }, {\n    async close (err) {\n      destination.end()\n      await once(destination, 'close')\n    }\n  })\n}\n```\n\nor using Node.js streams and CommonJS:\n\n```js\n'use strict'\n\nconst build = require('pino-abstract-transport')\nconst SonicBoom = require('sonic-boom')\n\nmodule.exports = function (opts) {\n  const destination = new SonicBoom({ dest: opts.destination || 1, sync: false })\n  return build(function (source) {\n    source.pipe(destination)\n  }, {\n    close (err, cb) {\n      destination.end()\n      destination.on('close', cb.bind(null, err))\n    }\n  })\n}\n```\n\n(It is possible to use the async iterators with CommonJS and streams with ESM.)\n\nTo consume async iterators in batches, consider using the [hwp](https://github.com/mcollina/hwp) library.\n\nThe `close()` function is needed to make sure that the stream is closed and flushed when its\ncallback is called or the returned promise resolves. Otherwise, log lines will be lost.\n\n### Writing to a custom transport & stdout\n\nIn case you want to both use a custom transport, and output the log entries with default processing to STDOUT, you can use 'pino/file' transport configured with `destination: 1`:\n\n```js\n    const transports = [\n      {\n        target: 'pino/file',\n        options: { destination: 1 } // this writes to STDOUT\n      },\n      {\n        target: 'my-custom-transport',\n        options: { someParameter: true } \n      }\n    ]\n\n    const logger = pino(pino.transport({ targets: transports }))\n```\n\n### Creating a transport pipeline\n\nAs an example, the following transport returns a `Transform` stream:\n\n```js\nimport build from 'pino-abstract-transport'\nimport { pipeline, Transform } from 'node:stream'\nexport default async function (options) {\n  return build(function (source) {\n    const myTransportStream = new Transform({\n      // Make sure autoDestroy is set,\n      // this is needed in Node v12 or when using the\n      // readable-stream module.\n      autoDestroy: true,\n\n      objectMode: true,\n      transform (chunk, enc, cb) {\n\n        // modifies the payload somehow\n        chunk.service = 'pino'\n\n        // stringify the payload again\n        this.push(`${JSON.stringify(chunk)}\\n`)\n        cb()\n      }\n    })\n    pipeline(source, myTransportStream, () => {})\n    return myTransportStream\n  }, {\n    // This is needed to be able to pipeline transports.\n    enablePipelining: true\n  })\n}\n```\n\nThen you can pipeline them with:\n\n```js\nimport pino from 'pino'\n\nconst logger = pino({\n  transport: {\n    pipeline: [{\n      target: './my-transform.js'\n    }, {\n      // Use target: 'pino/file' with STDOUT descriptor 1 to write\n      // logs without any change.\n      target: 'pino/file',\n      options: { destination: 1 }\n    }]\n  }\n})\n\nlogger.info('hello world')\n```\n\n__NOTE: there is no \"default\" destination for a pipeline but\na terminating target, i.e. a `Writable` stream.__\n\n### TypeScript compatibility\n\nPino provides support for transports written in TypeScript.\n\n#### Node.js 22+ with Type Stripping\n\nStarting with Node.js 22.6.0, you can use TypeScript transports directly with native type stripping support. This provides full ESM support without any transpilation or additional tooling:\n\n```ts\n// my-transport.mts\nimport { createWriteStream } from 'node:fs'\n\nexport default (options: { destination: string }) => {\n  return createWriteStream(options.destination)\n}\n```\n\n```js\n// app.js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: './my-transport.mts',\n  options: { destination: '/path/to/file' }\n})\npino(transport)\n```\n\n**Version requirements:**\n\n- **Node.js 22.6.0 - 22.17.x**: Use the `--experimental-strip-types` flag:\n  ```sh\n  node --experimental-strip-types app.ts\n  ```\n\n- **Node.js 22.18.0+ and 24.0.0+**: Type stripping is enabled by default, no flag needed:\n  ```sh\n  node app.ts\n  ```\n\n**Important notes:**\n- Use the `.mts` extension for TypeScript ESM modules to ensure proper module resolution\n- Alternatively, you can use `.ts` extension if your `package.json` has `\"type\": \"module\"`, but this requires your entire application to use ESM\n- Type stripping is not available in Node.js 20.x or earlier versions\n- This approach provides the cleanest TypeScript experience with full ESM support and no build step required\n\n#### Using TS-Node (Legacy)\n\nFor older Node.js versions, you can use tools such as [TS-Node](https://typestrong.org/ts-node/) to execute TypeScript\ncode without explicit transpilation, but there are some known caveats:\n- For \"pure\" TypeScript code, ES imports are not fully supported (ES imports are\n  supported once the code is transpiled).\n- Only TS-Node is supported. Other TypeScript loaders like [TSM](https://github.com/lukeed/tsm) are not currently supported.\n- Running transports TypeScript code on TS-Node may be problematic on\n  Windows systems.\n\n#### Transpiled TypeScript (Recommended for Production)\n\nFor maximum compatibility and production use, it's still recommended to transpile\nTypeScript transports to JavaScript before deployment.\n\n### Notable transports\n\n#### `pino/file`\n\nThe `pino/file` transport routes logs to a file (or file descriptor).\n\nThe `options.destination` property may be set to specify the desired file destination.\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino/file',\n  options: { destination: '/path/to/file' }\n})\npino(transport)\n```\n\nBy default, the `pino/file` transport assumes the directory of the destination file exists. If it does not exist, the transport will throw an error when it attempts to open the file for writing. The `mkdir` option may be set to `true` to configure the transport to create the directory, if it does not exist, before opening the file for writing.\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino/file',\n  options: { destination: '/path/to/file', mkdir: true }\n})\npino(transport)\n```\n\nBy default, the `pino/file` transport appends to the destination file if it exists. The `append` option may be set to `false` to configure the transport to truncate the file upon opening it for writing.\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino/file',\n  options: { destination: '/path/to/file', append: false }\n})\npino(transport)\n```\n\nThe `options.destination` property may also be a number to represent a file descriptor. Typically this would be `1` to write to STDOUT or `2` to write to STDERR. If `options.destination` is not set, it defaults to `1` which means logs will be written to STDOUT. If `options.destination` is a string integer, e.g. `'1'`, it will be coerced to a number and used as a file descriptor. If this is not desired, provide a full path, e.g. `/tmp/1`.\n\nThe difference between using the `pino/file` transport builtin and using `pino.destination` is that `pino.destination` runs in the main thread, whereas `pino/file` sets up `pino.destination` in a worker thread.\n\n#### `pino-pretty`\n\nThe [`pino-pretty`][pino-pretty] transport prettifies logs.\n\nBy default the `pino-pretty` builtin logs to STDOUT.\n\nThe `options.destination` property may be set to log pretty logs to a file descriptor or file. The following would send the prettified logs to STDERR:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino-pretty',\n  options: { destination: 1 } // use 2 for stderr\n})\npino(transport)\n```\n\n### Asynchronous startup\n\nThe new transports boot asynchronously and calling `process.exit()` before the transport\nstarts will cause logs to not be delivered.\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  targets: [\n    { target: '/absolute/path/to/my-transport.mjs', level: 'error' },\n    { target: 'some-file-transport', options: { destination: '/dev/null' } }\n  ]\n})\nconst logger = pino(transport)\n\nlogger.info('hello')\n\n// If logs are printed before the transport is ready when process.exit(0) is called,\n// they will be lost.\ntransport.on('ready', function () {\n  process.exit(0)\n})\n```\n\n## Legacy Transports\n\nA legacy Pino \"transport\" is a supplementary tool that consumes Pino logs.\n\nConsider the following example for creating a transport:\n\n```js\nconst { pipeline, Writable } = require('node:stream')\nconst split = require('split2')\n\nconst myTransportStream = new Writable({\n  write (chunk, enc, cb) {\n  // apply a transform and send to STDOUT\n  console.log(chunk.toString().toUpperCase())\n  cb()\n  }\n})\n\npipeline(process.stdin, split(JSON.parse), myTransportStream)\n```\n\nThe above defines our \"transport\" as the file `my-transport-process.js`.\n\nLogs can now be consumed using shell piping:\n\n```sh\nnode my-app-which-logs-stuff-to-stdout.js | node my-transport-process.js\n```\n\nIdeally, a transport should consume logs in a separate process to the application,\nUsing transports in the same process causes unnecessary load and slows down\nNode's single-threaded event loop.\n\n## Known Transports\n\nPRs to this document are welcome for any new transports!\n\n### Pino v7+ Compatible\n\n+ [@axiomhq/pino](#@axiomhq/pino)\n+ [@logtail/pino](#@logtail/pino)\n+ [@macfja/pino-fingers-crossed](#macfja-pino-fingers-crossed)\n+ [@openobserve/pino-openobserve](#pino-openobserve)\n+ [datadog-logger-integrations](#datadog-logger-integrations)\n+ [pino-airbrake-transport](#pino-airbrake-transport)\n+ [pino-axiom](#pino-axiom)\n+ [pino-discord-webhook](#pino-discord-webhook)\n+ [pino-elasticsearch](#pino-elasticsearch)\n+ [pino-hana](#pino-hana)\n+ [pino-logflare](#pino-logflare)\n+ [pino-logfmt](#pino-logfmt)\n+ [pino-loki](#pino-loki)\n+ [pino-opentelemetry-transport](#pino-opentelemetry-transport)\n+ [pino-pretty](#pino-pretty)\n+ [pino-roll](#pino-roll)\n+ [pino-seq-transport](#pino-seq-transport)\n+ [pino-sentry-transport](#pino-sentry-transport)\n+ [Sentry Native SDK Integration](#sentry-native-integration)\n+ [pino-slack-webhook](#pino-slack-webhook)\n+ [pino-telegram-webhook](#pino-telegram-webhook)\n+ [pino-yc-transport](#pino-yc-transport)\n\n### Legacy\n\n+ [pino-applicationinsights](#pino-applicationinsights)\n+ [pino-azuretable](#pino-azuretable)\n+ [pino-cloudwatch](#pino-cloudwatch)\n+ [pino-couch](#pino-couch)\n+ [pino-datadog](#pino-datadog)\n+ [pino-gelf](#pino-gelf)\n+ [pino-http-send](#pino-http-send)\n+ [pino-kafka](#pino-kafka)\n+ [pino-logdna](#pino-logdna)\n+ [pino-loki](#pino-loki)\n+ [pino-mq](#pino-mq)\n+ [pino-mysql](#pino-mysql)\n+ [pino-papertrail](#pino-papertrail)\n+ [pino-pg](#pino-pg)\n+ [pino-redis](#pino-redis)\n+ [pino-sentry](#pino-sentry)\n+ [pino-seq](#pino-seq)\n+ [pino-socket](#pino-socket)\n+ [pino-stackdriver](#pino-stackdriver)\n+ [pino-syslog](#pino-syslog)\n+ [pino-websocket](#pino-websocket)\n\n\n<a id=\"@axiomhq/pino\"></a>\n### @axiomhq/pino\n\n[@axiomhq/pino](https://www.npmjs.com/package/@axiomhq/pino) is the official [Axiom](https://axiom.co/) transport for Pino, using [axiom-js](https://github.com/axiomhq/axiom-js).\n\n```javascript\nimport pino from 'pino';\n\nconst logger = pino(\n  { level: 'info' },\n  pino.transport({\n    target: '@axiomhq/pino',\n    options: {\n      dataset: process.env.AXIOM_DATASET,\n      token: process.env.AXIOM_TOKEN,\n    },\n  }),\n);\n```\n\nthen you can use the logger as usual:\n\n```js\nlogger.info('Hello from pino!');\n```\n\nFor further examples, head over to the [examples](https://github.com/axiomhq/axiom-js/tree/main/examples/pino) directory.\n\n<a id=\"@logtail/pino\"></a>\n### @logtail/pino\n\nThe [@logtail/pino](https://www.npmjs.com/package/@logtail/pino) NPM package is a transport that forwards logs to [Logtail](https://logtail.com) by [Better Stack](https://betterstack.com).\n\n[Quick start guide ⇗](https://betterstack.com/docs/logs/javascript/pino)\n\n<a id=\"macfja-pino-fingers-crossed\"></a>\n### @macfja/pino-fingers-crossed\n\n[@macfja/pino-fingers-crossed](https://github.com/MacFJA/js-pino-fingers-crossed) is a Pino v7+ transport that holds logs until a log level is reached, allowing to only have logs when it matters.\n\n```js\nconst pino = require('pino');\nconst { default: fingersCrossed, enable } = require('@macfja/pino-fingers-crossed')\n\nconst logger = pino(fingersCrossed());\n\nlogger.info('Will appear immedialty')\nlogger.error('Will appear immedialty')\n\nlogger.setBindings({ [enable]: 50 })\nlogger.info('Will NOT appear immedialty')\nlogger.info('Will NOT appear immedialty')\nlogger.error('Will appear immedialty as well as the 2 previous messages') // error log are level 50\nlogger.info('Will NOT appear')\nlogger.info({ [enable]: false }, 'Will appear immedialty')\nlogger.info('Will NOT appear')\n```\n<a id=\"pino-openobserve\"></a>\n### @openobserve/pino-openobserve\n\n[@openobserve/pino-openobserve](https://github.com/openobserve/pino-openobserve) is a \nPino v7+ transport that will send logs to an \n[OpenObserve](https://openobserve.ai) instance.\n\n```\nconst pino = require('pino');\nconst OpenobserveTransport = require('@openobserve/pino-openobserve');\n\nconst logger = pino({\n  level: 'info',\n  transport: {\n    target: OpenobserveTransport,\n    options: {\n      url: 'https://your-openobserve-server.com',\n      organization: 'your-organization',\n      streamName: 'your-stream',\n      auth: {\n        username: 'your-username',\n        password: 'your-password',\n      },\n    },\n  },\n});\n```\n\nFor full documentation check the [README](https://github.com/openobserve/pino-openobserve).\n\n<a id=\"pino-airbrake-transport\"></a>\n### pino-airbrake-transport\n\n[pino-airbrake-transport][pino-airbrake-transport] is a Pino v7+ compatible transport to forward log events to [Airbrake][Airbrake]\nfrom a dedicated worker:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino-airbrake-transport',\n  options: {\n    airbrake: {\n      projectId: 1,\n      projectKey: \"REPLACE_ME\",\n      environment: \"production\",\n      // additional options for airbrake\n      performanceStats: false,\n    },\n  },\n  level: \"error\", // minimum log level that should be sent to airbrake\n})\npino(transport)\n```\n\n[pino-airbrake-transport]: https://github.com/enricodeleo/pino-airbrake-transport\n[Airbrake]: https://airbrake.io/\n\n<a id=\"pino-applicationinsights\"></a>\n### pino-applicationinsights\nThe [pino-applicationinsights](https://www.npmjs.com/package/pino-applicationinsights) module is a transport that will forward logs to [Azure Application Insights](https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview).\n\nGiven an application `foo` that logs via pino, you would use `pino-applicationinsights` like so:\n\n``` sh\n$ node foo | pino-applicationinsights --key blablabla\n```\n\nFor full documentation of command line switches read [README](https://github.com/ovhemert/pino-applicationinsights#readme)\n\n<a id=\"pino-axiom\"></a>\n### pino-axiom\n\n[pino-axiom](https://www.npmjs.com/package/pino-axiom) is a transport that will forward logs to [Axiom](https://axiom.co).\n\n```javascript\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino-axiom',\n  options: {\n    orgId: 'YOUR-ORG-ID', \n    token: 'YOUR-TOKEN', \n    dataset: 'YOUR-DATASET', \n  },\n})\npino(transport)\n```\n\n<a id=\"pino-azuretable\"></a>\n### pino-azuretable\nThe [pino-azuretable](https://www.npmjs.com/package/pino-azuretable) module is a transport that will forward logs to the [Azure Table Storage](https://azure.microsoft.com/en-us/services/storage/tables/).\n\nGiven an application `foo` that logs via pino, you would use `pino-azuretable` like so:\n\n``` sh\n$ node foo | pino-azuretable --account storageaccount --key blablabla\n```\n\nFor full documentation of command line switches read [README](https://github.com/ovhemert/pino-azuretable#readme)\n\n<a id=\"pino-cloudwatch\"></a>\n### pino-cloudwatch\n\n[pino-cloudwatch][pino-cloudwatch] is a transport that buffers and forwards logs to [Amazon CloudWatch][].\n\n```sh\n$ node app.js | pino-cloudwatch --group my-log-group\n```\n\n[pino-cloudwatch]: https://github.com/dbhowell/pino-cloudwatch\n[Amazon CloudWatch]: https://aws.amazon.com/cloudwatch/\n\n<a id=\"pino-couch\"></a>\n### pino-couch\n\n[pino-couch][pino-couch] uploads each log line as a [CouchDB][CouchDB] document.\n\n```sh\n$ node app.js | pino-couch -U https://couch-server -d mylogs\n```\n\n[pino-couch]: https://github.com/IBM/pino-couch\n[CouchDB]: https://couchdb.apache.org\n\n<a id=\"pino-datadog\"></a>\n### pino-datadog\nThe [pino-datadog](https://www.npmjs.com/package/pino-datadog) module is a transport that will forward logs to [DataDog](https://www.datadoghq.com/) through its API.\n\nGiven an application `foo` that logs via pino, you would use `pino-datadog` like so:\n\n``` sh\n$ node foo | pino-datadog --key blablabla\n```\n\nFor full documentation of command line switches read [README](https://github.com/ovhemert/pino-datadog#readme)\n\n<a id=\"datadog-logger-integrations\"></a>\n### datadog-logger-integrations\n\n[datadog-logger-integrations][datadog-logger-integrations] is a Pino v7+ compatible transport to forward log events to [Datadog][Datadog]\nfrom a dedicated worker:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'datadog-logger-integrations',\n  options: {\n    ddClientConfig: {\n      authMethods: {\n        apiKeyAuth: <your datadog API key>\n      }\n    },\n  },\n  level: \"error\", // minimum log level that should be sent to datadog\n})\npino(transport)\n```\n\n[datadog-logger-integrations]: https://github.com/marklai1998/datadog-logger-integrations\n[Datadog]: https://www.datadoghq.com/\n\n#### Logstash\n\nThe [pino-socket][pino-socket] module can also be used to upload logs to\n[Logstash][logstash] via:\n\n```\n$ node app.js | pino-socket -a 127.0.0.1 -p 5000 -m tcp\n```\n\nAssuming logstash is running on the same host and configured as\nfollows:\n\n```\ninput {\n  tcp {\n    port => 5000\n  }\n}\n\nfilter {\n  json {\n    source => \"message\"\n  }\n}\n\noutput {\n  elasticsearch {\n    hosts => \"127.0.0.1:9200\"\n  }\n}\n```\n\nSee <https://www.elastic.co/guide/en/kibana/current/setup.html> to learn\nhow to setup [Kibana][kibana].\n\nFor Docker users, see\nhttps://github.com/deviantony/docker-elk to setup an ELK stack.\n\n<a id=\"pino-discord-webhook\"></a>\n### pino-discord-webhook\n\n[pino-discord-webhook](https://github.com/fabulousgk/pino-discord-webhook) is a  Pino v7+ compatible transport to forward log events to a [Discord](http://discord.com) webhook from a dedicated worker. \n\n```js\nimport pino from 'pino'\n\nconst logger = pino({\n  transport: {\n    target: 'pino-discord-webhook',\n    options: {\n      webhookUrl: 'https://discord.com/api/webhooks/xxxx/xxxx',\n    }\n  }\n})\n```\n\n<a id=\"pino-elasticsearch\"></a>\n### pino-elasticsearch\n\n[pino-elasticsearch][pino-elasticsearch] uploads the log lines in bulk\nto [Elasticsearch][elasticsearch], to be displayed in [Kibana][kibana].\n\nIt is extremely simple to use and setup\n\n```sh\n$ node app.js | pino-elasticsearch\n```\n\nAssuming Elasticsearch is running on localhost.\n\nTo connect to an external Elasticsearch instance (recommended for production):\n\n* Check that `network.host` is defined in the `elasticsearch.yml` configuration file. See [Elasticsearch Network Settings documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#common-network-settings) for more details.\n* Launch:\n\n```sh\n$ node app.js | pino-elasticsearch --node http://192.168.1.42:9200\n```\n\nAssuming Elasticsearch is running on `192.168.1.42`.\n\nTo connect to AWS Elasticsearch:\n\n```sh\n$ node app.js | pino-elasticsearch --node https://es-url.us-east-1.es.amazonaws.com --es-version 6\n```\n\nThen [create an index pattern](https://www.elastic.co/guide/en/kibana/current/setup.html) on `'pino'` (the default index key for `pino-elasticsearch`) on the Kibana instance.\n\n[pino-elasticsearch]: https://github.com/pinojs/pino-elasticsearch\n[elasticsearch]: https://www.elastic.co/products/elasticsearch\n[kibana]: https://www.elastic.co/products/kibana\n\n<a id=\"pino-gelf\"></a>\n### pino-gelf\n\nPino GELF ([pino-gelf]) is a transport for the Pino logger. Pino GELF receives Pino logs from stdin and transforms them into [GELF format][gelf] before sending them to a remote [Graylog server][graylog] via UDP.\n\n```sh\n$ node your-app.js | pino-gelf log\n```\n\n[pino-gelf]: https://github.com/pinojs/pino-gelf\n[gelf]: https://docs.graylog.org/en/2.1/pages/gelf.html\n[graylog]: https://www.graylog.org/\n\n<a id=\"pino-hana\"></a>\n### pino-hana\n[pino-hana](https://github.com/HiImGiovi/pino-hana) is a Pino v7+ transport that save pino logs to a SAP HANA database.\n```js\nconst pino = require('pino')\nconst logger = pino({\n  transport: {\n    target: 'pino-hana',\n    options: {\n      connectionOptions: {\n        host: <hana db host>,\n        port: <hana db port>,\n        user: <hana db user>,\n        password: <hana db password>,\n      },\n      schema: <schema of the table in which you want to save the logs>,\n      table: <table in which you want to save the logs>,\n    },\n  },\n})\n\nlogger.info('hi') // this log will be saved into SAP HANA\n```\nFor more detailed information about its usage please check the official [documentation](https://github.com/HiImGiovi/pino-hana#readme).\n\n<a id=\"pino-http-send\"></a>\n### pino-http-send\n\n[pino-http-send](https://npmjs.com/package/pino-http-send) is a configurable and low overhead\ntransport that will batch logs and send to a specified URL.\n\n```console\n$ node app.js | pino-http-send -u http://localhost:8080/logs\n```\n\n<a id=\"pino-kafka\"></a>\n### pino-kafka\n\n[pino-kafka](https://github.com/ayZagen/pino-kafka) transport to send logs to [Apache Kafka](https://kafka.apache.org/).\n\n```sh\n$ node index.js | pino-kafka -b 10.10.10.5:9200 -d mytopic\n```\n\n<a id=\"pino-logdna\"></a>\n### pino-logdna\n\n[pino-logdna](https://github.com/logdna/pino-logdna) transport to send logs to [LogDNA](https://logdna.com).\n\n```sh\n$ node index.js | pino-logdna --key YOUR_INGESTION_KEY\n```\n\nTags and other metadata can be included using the available command line options. See the [pino-logdna README](https://github.com/logdna/pino-logdna#options) for a full list.\n\n<a id=\"pino-logflare\"></a>\n### pino-logflare\n\n[pino-logflare](https://github.com/Logflare/pino-logflare) transport to send logs to a [Logflare](https://logflare.app) `source`.\n\n```sh\n$ node index.js | pino-logflare --key YOUR_KEY --source YOUR_SOURCE\n```\n\n<a id=\"pino-logfmt\"></a>\n### pino-logfmt\n\n[pino-logfmt](https://github.com/botflux/pino-logfmt) is a Pino v7+ transport that formats logs into [logfmt](https://brandur.org/logfmt). This transport can output the formatted logs to stdout or file.\n\n```js\nimport pino from 'pino'\n\nconst logger = pino({\n  transport: {\n    target: 'pino-logfmt'\n  }\n})\n```\n\n<a id=\"pino-loki\"></a>\n### pino-loki\npino-loki is a transport that will forwards logs into [Grafana Loki](https://grafana.com/oss/loki/).\nCan be used in CLI version in a separate process or in a dedicated worker:\n\nCLI :\n```console\nnode app.js | pino-loki --hostname localhost:3100 --labels='{ \"application\": \"my-application\"}' --user my-username --password my-password\n```\n\nWorker :\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino-loki',\n  options: { host: 'localhost:3100' }\n})\npino(transport)\n```\n\nFor full documentation and configuration, see the [README](https://github.com/Julien-R44/pino-loki).\n\n<a id=\"pino-mq\"></a>\n### pino-mq\n\nThe `pino-mq` transport will take all messages received on `process.stdin` and send them over a message bus using JSON serialization.\n\nThis is useful for:\n\n* moving backpressure from application to broker\n* transforming messages pressure to another component\n\n```\nnode app.js | pino-mq -u \"amqp://guest:guest@localhost/\" -q \"pino-logs\"\n```\n\nAlternatively, a configuration file can be used:\n\n```\nnode app.js | pino-mq -c pino-mq.json\n```\n\nA base configuration file can be initialized with:\n\n```\npino-mq -g\n```\n\nFor full documentation of command line switches and configuration see [the `pino-mq` README](https://github.com/itavy/pino-mq#readme)\n\n<a id=\"pino-mysql\"></a>\n### pino-mysql\n\n[pino-mysql][pino-mysql] loads pino logs into [MySQL][MySQL] and [MariaDB][MariaDB].\n\n```sh\n$ node app.js | pino-mysql -c db-configuration.json\n```\n\n`pino-mysql` can extract and save log fields into corresponding database fields\nand/or save the entire log stream as a [JSON Data Type][JSONDT].\n\nFor full documentation and command line switches read the [README][pino-mysql].\n\n[pino-mysql]: https://www.npmjs.com/package/pino-mysql\n[MySQL]: https://www.mysql.com/\n[MariaDB]: https://mariadb.org/\n[JSONDT]: https://dev.mysql.com/doc/refman/8.0/en/json.html\n\n<a id=\"pino-opentelemetry-transport\"></a>\n### pino-opentelemetry-transport\n\n[pino-opentelemetry-transport](https://www.npmjs.com/package/pino-opentelemetry-transport) is a transport that will forward logs to an [OpenTelemetry log collector](https://opentelemetry.io/docs/collector/) using [OpenTelemetry JS instrumentation](https://opentelemetry.io/docs/instrumentation/js/).\n\n```javascript\nconst pino = require('pino')\n\nconst transport = pino.transport({\n  target: 'pino-opentelemetry-transport',\n  options: {\n    resourceAttributes: {\n      'service.name': 'test-service',\n      'service.version': '1.0.0'\n    }\n  }\n})\n\npino(transport)\n```\n\nDocumentation on running a minimal example is available in the [README](https://github.com/Vunovati/pino-opentelemetry-transport#minimalistic-example).\n\n<a id=\"pino-papertrail\"></a>\n### pino-papertrail\npino-papertrail is a transport that will forward logs to the [papertrail](https://papertrailapp.com) log service through an UDPv4 socket.\n\nGiven an application `foo` that logs via pino, and a papertrail destination that collects logs on port UDP `12345` on address `bar.papertrailapp.com`, you would use `pino-papertrail`\nlike so:\n\n```\nnode yourapp.js | pino-papertrail --host bar.papertrailapp.com --port 12345 --appname foo\n```\n\n\nfor full documentation of command line switches read [README](https://github.com/ovhemert/pino-papertrail#readme)\n\n<a id=\"pino-pg\"></a>\n### pino-pg\n[pino-pg](https://www.npmjs.com/package/pino-pg) stores logs into PostgreSQL.\nFull documentation in the [README](https://github.com/Xstoudi/pino-pg).\n\n<a id=\"pino-redis\"></a>\n### pino-redis\n\n[pino-redis][pino-redis] loads pino logs into [Redis][Redis].\n\n```sh\n$ node app.js | pino-redis -U redis://username:password@localhost:6379\n```\n\n[pino-redis]: https://github.com/buianhthang/pino-redis\n[Redis]: https://redis.io/\n\n<a id=\"pino-roll\"></a>\n### pino-roll\n\n`pino-roll` is a Pino transport that automatically rolls your log files based on size or time frequency.\n\n```js\nimport { join } from 'path';\nimport pino from 'pino';\n\nconst transport = pino.transport({\n  target: 'pino-roll',\n  options: { file: join('logs', 'log'), frequency: 'daily', mkdir: true }\n});\n\nconst logger = pino(transport);\n```\n\nthen you can use the logger as usual:\n\n```js\nlogger.info('Hello from pino-roll!');\n```\nFor full documentation check the [README](https://github.com/mcollina/pino-roll?tab=readme-ov-file#pino-roll).\n\n<a id=\"pino-sentry\"></a>\n### pino-sentry\n\n[pino-sentry][pino-sentry] loads pino logs into [Sentry][Sentry].\n\n```sh\n$ node app.js | pino-sentry --dsn=https://******@sentry.io/12345\n```\n\nFor full documentation of command line switches see the [pino-sentry README](https://github.com/aandrewww/pino-sentry/blob/master/README.md).\n\n[pino-sentry]: https://www.npmjs.com/package/pino-sentry\n[Sentry]: https://sentry.io/\n\n<a id=\"pino-sentry-transport\"></a>\n### pino-sentry-transport\n\n[pino-sentry-transport][pino-sentry-transport] is a Pino v7+ compatible transport to forward log events to [Sentry][Sentry]\nfrom a dedicated worker:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: 'pino-sentry-transport',\n  options: {\n    sentry: {\n      dsn: 'https://******@sentry.io/12345',\n    }\n  }\n})\npino(transport)\n```\n\n[pino-sentry-transport]: https://github.com/tomer-yechiel/pino-sentry-transport\n[Sentry]: https://sentry.io/\n\n<a id=\"sentry-native-integration\"></a>\n### Sentry Native SDK Integration\n\nAs an alternative to using a Pino transport, Sentry's Node.js SDK (v10.18.0+) provides a native `pinoIntegration` that instruments Pino directly. This approach captures logs within the Sentry SDK rather than forwarding them through a separate worker process.\n\n```js\nconst Sentry = require('@sentry/node')\nconst pino = require('pino')\n\nSentry.init({\n  dsn: 'https://******@sentry.io/12345',\n  enableLogs: true,\n  integrations: [Sentry.pinoIntegration()],\n})\n\nconst logger = pino()\nlogger.info('This log will be captured by Sentry')\n```\n\nThe integration supports configuring which log levels are captured as Sentry logs or errors:\n\n```js\nSentry.init({\n  dsn: 'https://******@sentry.io/12345',\n  enableLogs: true,\n  integrations: [\n    Sentry.pinoIntegration({\n      // Capture these levels as Sentry logs\n      log: { levels: ['info', 'warn', 'error'] },\n      // Capture these levels as Sentry errors\n      error: { levels: ['error', 'fatal'], handled: true }\n    })\n  ],\n})\n```\n\n**Note:** This integration only works in the Node.js runtime. Requires Sentry SDK version 10.18.0 or higher and pino version 8.0.0 or higher. For full documentation, see the [Sentry Pino integration docs][sentry-pino-docs].\n\n[sentry-pino-docs]: https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/pino/\n\n<a id=\"pino-seq\"></a>\n### pino-seq\n\n[pino-seq][pino-seq] supports both out-of-process and in-process log forwarding to [Seq][Seq].\n\n```sh\n$ node app.js | pino-seq --serverUrl http://localhost:5341 --apiKey 1234567890 --property applicationName=MyNodeApp\n```\n\n[pino-seq]: https://www.npmjs.com/package/pino-seq\n[Seq]: https://datalust.co/seq\n\n<a id=\"pino-seq-transport\"></a>\n### pino-seq-transport\n\n[pino-seq-transport][pino-seq-transport] is a Pino v7+ compatible transport to forward log events to [Seq][Seq]\nfrom a dedicated worker:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: '@autotelic/pino-seq-transport',\n  options: { serverUrl: 'http://localhost:5341' }\n})\npino(transport)\n```\n\n[pino-seq-transport]: https://github.com/autotelic/pino-seq-transport\n[Seq]: https://datalust.co/seq\n\n<a id=\"pino-slack-webhook\"></a>\n### pino-slack-webhook\n\n[pino-slack-webhook][pino-slack-webhook] is a Pino v7+ compatible transport to forward log events to [Slack][Slack]\nfrom a dedicated worker:\n\n```js\nconst pino = require('pino')\nconst transport = pino.transport({\n  target: '@youngkiu/pino-slack-webhook',\n  options: {\n    webhookUrl: 'https://hooks.slack.com/services/xxx/xxx/xxx',\n    channel: '#pino-log',\n    username: 'webhookbot',\n    icon_emoji: ':ghost:'\n  }\n})\npino(transport)\n```\n\n[pino-slack-webhook]: https://github.com/youngkiu/pino-slack-webhook\n[Slack]: https://slack.com/\n\n[pino-pretty]: https://github.com/pinojs/pino-pretty\n\nFor full documentation of command line switches read the [README](https://github.com/abeai/pino-websocket#readme).\n\n<a id=\"pino-socket\"></a>\n### pino-socket\n\n[pino-socket][pino-socket] is a transport that will forward logs to an IPv4\nUDP or TCP socket.\n\nAs an example, use `socat` to fake a listener:\n\n```sh\n$ socat -v udp4-recvfrom:6000,fork exec:'/bin/cat'\n```\n\nThen run an application that uses `pino` for logging:\n\n```sh\n$ node app.js | pino-socket -p 6000\n```\n\nLogs from the application should be observed on both consoles.\n\n[pino-socket]: https://www.npmjs.com/package/pino-socket\n\n<a id=\"pino-stackdriver\"></a>\n### pino-stackdriver\nThe [pino-stackdriver](https://www.npmjs.com/package/pino-stackdriver) module is a transport that will forward logs to the [Google Stackdriver](https://cloud.google.com/logging/) log service through its API.\n\nGiven an application `foo` that logs via pino, a stackdriver log project `bar`, and credentials in the file `/credentials.json`, you would use `pino-stackdriver`\nlike so:\n\n``` sh\n$ node foo | pino-stackdriver --project bar --credentials /credentials.json\n```\n\nFor full documentation of command line switches read [README](https://github.com/ovhemert/pino-stackdriver#readme)\n\n<a id=\"pino-syslog\"></a>\n### pino-syslog\n\n[pino-syslog][pino-syslog] is a transforming transport that converts\n`pino` NDJSON logs to [RFC3164][rfc3164] compatible log messages. The `pino-syslog` module does not\nforward the logs anywhere, it merely re-writes the messages to `stdout`. But\nwhen used in combination with `pino-socket` the log messages can be relayed to a syslog server:\n\n```sh\n$ node app.js | pino-syslog | pino-socket -a syslog.example.com\n```\n\nExample output for the \"hello world\" log:\n\n```\n<134>Apr  1 16:44:58 MacBook-Pro-3 none[94473]: {\"pid\":94473,\"hostname\":\"MacBook-Pro-3\",\"level\":30,\"msg\":\"hello world\",\"time\":1459529098958}\n```\n\n[pino-syslog]: https://www.npmjs.com/package/pino-syslog\n[rfc3164]: https://tools.ietf.org/html/rfc3164\n[logstash]: https://www.elastic.co/products/logstash\n\n<a id=\"pino-telegram-webhook\"></a>\n### pino-telegram-webhook\n\n[pino-telegram-webhook](https://github.com/Jhon-Mosk/pino-telegram-webhook) is a Pino v7+ transport for sending messages to [Telegram](https://telegram.org/). \n\n```js\nconst pino = require('pino');\n\nconst logger = pino({\n  transport: {\n    target: 'pino-telegram-webhook',\n    level: 'error',\n    options: {\n      chatId: -1234567890,\n      botToken: \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n      extra: {\n              parse_mode: \"HTML\",\n            },\n    },\n  },\n})\n\nlogger.error('<b>test log!</b>');\n```\n\nThe `extra` parameter is optional. Parameters that the method [`sendMessage`](https://core.telegram.org/bots/api#sendmessage) supports can be passed to it.\n\n<a id=\"pino-websocket\"></a>\n### pino-websocket\n\n[pino-websocket](https://www.npmjs.com/package/@abeai/pino-websocket) is a transport that will forward each log line to a websocket server.\n\n```sh\n$ node app.js | pino-websocket -a my-websocket-server.example.com -p 3004\n```\n\nFor full documentation of command line switches read the [README](https://github.com/abeai/pino-websocket#readme).\n\n<a id=\"pino-yc-transport\"></a>\n### pino-yc-transport\n\n[pino-yc-transport](https://github.com/Jhon-Mosk/pino-yc-transport) is a Pino v7+ transport for writing to [Yandex Cloud Logging](https://yandex.cloud/ru/services/logging) from serveless functions or containers.\n\n```js\nconst pino = require(\"pino\");\n\nconst config = {\n  level: \"debug\",\n  transport: {\n    target: \"pino-yc-transport\",\n  },\n};\n\nconst logger = pino(config);\n\nlogger.debug(\"some message\")\nlogger.debug({ foo: \"bar\" });\nlogger.debug(\"some message %o, %s\", { foo: \"bar\" }, \"baz\");\nlogger.info(\"info\");\nlogger.warn(\"warn\");\nlogger.error(\"error\");\nlogger.error(new Error(\"error\"));\nlogger.fatal(\"fatal\");\n```\n\n<a id=\"communication-between-pino-and-transport\"></a>\n## Communication between Pino and Transports\nHere we discuss some technical details of how Pino communicates with its [worker threads](https://nodejs.org/api/worker_threads.html).\n\nPino uses [`thread-stream`](https://github.com/pinojs/thread-stream) to create a stream for transports.\nWhen we create a stream with `thread-stream`, `thread-stream` spawns a [worker](https://github.com/pinojs/thread-stream/blob/f19ac8dbd602837d2851e17fbc7dfc5bbc51083f/index.js#L50-L60) (an independent JavaScript execution thread).\n\n### Error messages\nHow are error messages propagated from a transport worker to Pino?\n\nLet's assume we have a transport with an error listener:\n```js\n// index.js\nconst transport = pino.transport({\n  target: './transport.js'\n})\n\ntransport.on('error', err => {\n  console.error('error caught', err)\n})\n\nconst log = pino(transport)\n```\n\nWhen our worker emits an error event, the worker has listeners for it: [error](https://github.com/pinojs/thread-stream/blob/f19ac8dbd602837d2851e17fbc7dfc5bbc51083f/lib/worker.js#L59-L70) and [unhandledRejection](https://github.com/pinojs/thread-stream/blob/f19ac8dbd602837d2851e17fbc7dfc5bbc51083f/lib/worker.js#L135-L141). These listeners send the error message to the main thread where Pino is present.\n\nWhen Pino receives the error message, it further [emits](https://github.com/pinojs/thread-stream/blob/f19ac8dbd602837d2851e17fbc7dfc5bbc51083f/index.js#L349) the error message. Finally, the error message arrives at our `index.js` and is caught by our error listener.\n"
  },
  {
    "path": "docs/web.md",
    "content": "# Web Frameworks\n\nSince HTTP logging is a primary use case, Pino has first-class support for the Node.js\nweb framework ecosystem.\n\n- [Web Frameworks](#web-frameworks)\n  - [Pino with Fastify](#pino-with-fastify)\n  - [Pino with Express](#pino-with-express)\n  - [Pino with Hapi](#pino-with-hapi)\n  - [Pino with Restify](#pino-with-restify)\n  - [Pino with Koa](#pino-with-koa)\n  - [Pino with Node core `http`](#pino-with-node-core-http)\n  - [Pino with Nest](#pino-with-nest)\n  - [Pino with H3](#pino-with-h3)\n  - [Pino with Hono](#pino-with-hono)\n\n<a id=\"fastify\"></a>\n## Pino with Fastify\n\nThe Fastify web framework comes bundled with Pino by default, simply set Fastify's\n`logger` option to `true` and use `request.log` or `reply.log` for log messages that correspond\nto each request:\n\n```js\nconst fastify = require('fastify')({\n  logger: true\n})\n\nfastify.get('/', async (request, reply) => {\n  request.log.info('something')\n  return { hello: 'world' }\n})\n\nfastify.listen({ port: 3000 }, (err) => {\n  if (err) {\n    fastify.log.error(err)\n    process.exit(1)\n  }\n})\n```\n\nThe `logger` option can also be set to an object, which will be passed through directly\nas the [`pino` options object](/docs/api.md#options-object).\n\nSee the [fastify documentation](https://www.fastify.io/docs/latest/Reference/Logging/) for more information.\n\n<a id=\"express\"></a>\n## Pino with Express\n\n```sh\nnpm install pino-http\n```\n\n```js\nconst app = require('express')()\nconst pino = require('pino-http')()\n\napp.use(pino)\n\napp.get('/', function (req, res) {\n  req.log.info('something')\n  res.send('hello world')\n})\n\napp.listen(3000)\n```\n\nSee the [pino-http README](https://npm.im/pino-http) for more info.\n\n<a id=\"hapi\"></a>\n## Pino with Hapi\n\n```sh\nnpm install hapi-pino\n```\n\n```js\n'use strict'\n\nconst Hapi = require('@hapi/hapi')\nconst Pino = require('hapi-pino');\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  })\n\n  // Add the route\n  server.route({\n    method: 'GET',\n    path: '/',\n    handler: async function (request, h) {\n      // request.log is HAPI's standard way of logging\n      request.log(['a', 'b'], 'Request into hello world')\n\n      // a pino instance can also be used, 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(Pino)\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) => {\n  console.log(err)\n  process.exit(1)\n})\n```\n\nSee the [hapi-pino README](https://npm.im/hapi-pino) for more info.\n\n<a id=\"restify\"></a>\n## Pino with Restify\n\n```sh\nnpm install restify-pino-logger\n```\n\n```js\nconst server = require('restify').createServer({name: 'server'})\nconst pino = require('restify-pino-logger')()\n\nserver.use(pino)\n\nserver.get('/', function (req, res) {\n  req.log.info('something')\n  res.send('hello world')\n})\n\nserver.listen(3000)\n```\n\nSee the [restify-pino-logger README](https://npm.im/restify-pino-logger) for more info.\n\n<a id=\"koa\"></a>\n## Pino with Koa\n\n```sh\nnpm install koa-pino-logger\n```\n\n```js\nconst Koa = require('koa')\nconst app = new Koa()\nconst pino = require('koa-pino-logger')()\n\napp.use(pino)\n\napp.use((ctx) => {\n  ctx.log.info('something else')\n  ctx.body = 'hello world'\n})\n\napp.listen(3000)\n```\n\nSee the [koa-pino-logger README](https://github.com/pinojs/koa-pino-logger) for more info.\n\n<a id=\"http\"></a>\n## Pino with Node core `http`\n\n```sh\nnpm install pino-http\n```\n\n```js\nconst http = require('http')\nconst server = http.createServer(handle)\nconst logger = require('pino-http')()\n\nfunction handle (req, res) {\n  logger(req, res)\n  req.log.info('something else')\n  res.end('hello world')\n}\n\nserver.listen(3000)\n```\n\nSee the [pino-http README](https://npm.im/pino-http) for more info.\n\n\n<a id=\"nest\"></a>\n## Pino with Nest\n\n```sh\nnpm install nestjs-pino\n```\n\n```ts\nimport { NestFactory } from '@nestjs/core'\nimport { Controller, Get, Module } from '@nestjs/common'\nimport { LoggerModule, Logger } from 'nestjs-pino'\n\n@Controller()\nexport class AppController {\n  constructor(private readonly logger: Logger) {}\n\n  @Get()\n  getHello() {\n    this.logger.log('something')\n    return `Hello world`\n  }\n}\n\n@Module({\n  controllers: [AppController],\n  imports: [LoggerModule.forRoot()]\n})\nclass MyModule {}\n\nasync function bootstrap() {\n  const app = await NestFactory.create(MyModule)\n  await app.listen(3000)\n}\nbootstrap()\n```\n\nSee the [nestjs-pino README](https://npm.im/nestjs-pino) for more info.\n\n\n<a id=\"h3\"></a>\n## Pino with H3\n\n```sh\nnpm install pino-http h3\n```\n\nSave as `server.mjs`:\n\n```js\nimport { createApp, createRouter, eventHandler, fromNodeMiddleware } from \"h3\";\nimport pino from 'pino-http'\n\nexport const app = createApp();\n\nconst router = createRouter();\napp.use(router);\napp.use(fromNodeMiddleware(pino()))\n\napp.use(eventHandler((event) => {\n  event.node.req.log.info('something')\n  return 'hello world'\n}))\n\nrouter.get(\n  \"/\",\n  eventHandler((event) => {\n    return { path: event.path, message: \"Hello World!\" };\n  }),\n);\n```\n\nExecute `npx --yes listhen -w --open ./server.mjs`.\n\nSee the [pino-http README](https://npm.im/pino-http) for more info.\n\n\n<a id=\"hono\"></a>\n## Pino with Hono\n\n```sh\nnpm install pino pino-http hono\n```\n\n```js\nimport { serve } from '@hono/node-server';\nimport { Hono } from 'hono';\nimport { requestId } from 'hono/request-id';\nimport { pinoHttp } from 'pino-http';\n\nconst app = new Hono();\napp.use(requestId());\napp.use(async (c, next) => {\n  // pass hono's request-id to pino-http\n  c.env.incoming.id = c.var.requestId;\n\n  // map express style middleware to hono\n  await new Promise((resolve) => pinoHttp()(c.env.incoming, c.env.outgoing, () => resolve()));\n\n  c.set('logger', c.env.incoming.log);\n\n  await next();\n});\n\napp.get('/', (c) => {\n  c.var.logger.info('something');\n\n  return c.text('Hello Node.js!');\n});\n\nserve(app);\n```\n\nSee the [pino-http README](https://npm.im/pino-http) for more info.\n"
  },
  {
    "path": "docsify/sidebar.md",
    "content": "* [Readme](/)\n* [API](/docs/api.md)\n* [Browser API](/docs/browser.md)\n* [Redaction](/docs/redaction.md)\n* [Child Loggers](/docs/child-loggers.md)\n* [Transports](/docs/transports.md)\n* [Web Frameworks](/docs/web.md)\n* [Pretty Printing](/docs/pretty.md)\n* [Asynchronous Logging](/docs/asynchronous.md)\n* [Ecosystem](/docs/ecosystem.md)\n* [Benchmarks](/docs/benchmarks.md)\n* [Long Term Support](/docs/lts.md)\n* [Help](/docs/help.md)\n  * [Log rotation](/docs/help.md#rotate)\n  * [Reopening log files](/docs/help.md#reopening)\n  * [Saving to multiple files](/docs/help.md#multiple)\n  * [Log filtering](/docs/help.md#filter-logs)\n  * [Transports and systemd](/docs/help.md#transport-systemd)\n  * [Duplicate keys](/docs/help.md#dupe-keys)\n  * [Log levels as labels instead of numbers](/docs/help.md#level-string)\n  * [Pino with `debug`](/docs/help.md#debug)\n  * [Unicode and Windows terminal](/docs/help.md#windows)\n  * [Mapping Pino Log Levels to Google Cloud Logging (Stackdriver) Severity Levels](/docs/help.md#stackdriver)\n  * [Avoid Message Conflict](/docs/help.md#avoid-message-conflict)\n  * [Best performance for logging to `stdout`](/docs/help.md#best-performance-for-stdout)\n  * [Testing](/docs/help.md#testing)\n"
  },
  {
    "path": "eslint.config.js",
    "content": "'use strict'\n\nconst { defineConfig, globalIgnores } = require('eslint/config')\nconst neostandard = require('neostandard')\n\nmodule.exports = defineConfig([\n  neostandard({\n    ts: true\n  }),\n  globalIgnores([\n    'test/fixtures/syntax-error-esm.mjs',\n    'test/fixtures/ts/*cjs'\n  ]),\n  {\n    rules: {\n      'comma-dangle': ['error', 'never'],\n      'no-var': 'off'\n    }\n  },\n  {\n    files: ['pino.d.ts'],\n    rules: {\n      '@typescript-eslint/no-use-before-define': 'off',\n      '@typescript-eslint/no-unused-vars': 'off'\n    }\n  },\n  {\n    files: ['test/types/**/*'],\n    rules: {\n      '@typescript-eslint/no-unused-expressions': 'off',\n      '@typescript-eslint/no-unused-vars': 'off',\n      'n/handle-callback-err': 'off'\n    }\n  }\n])\n"
  },
  {
    "path": "examples/basic.js",
    "content": "'use strict'\n\n// Pino's primary usage writes ndjson to `stdout`:\nconst pino = require('..')()\n\n// However, if \"human readable\" output is desired,\n// `pino-pretty` can be provided as the destination\n// stream by uncommenting the following line in place\n// of the previous declaration:\n// const pino = require('..')(require('pino-pretty')())\n\npino.info('hello world')\npino.error('this is at error level')\npino.info('the answer is %d', 42)\npino.info({ obj: 42 }, 'hello world')\npino.info({ obj: 42, b: 2 }, 'hello world')\npino.info({ nested: { obj: 42 } }, 'nested')\nsetImmediate(() => {\n  pino.info('after setImmediate')\n})\npino.error(new Error('an error'))\n\nconst child = pino.child({ a: 'property' })\nchild.info('hello child!')\n\nconst childsChild = child.child({ another: 'property' })\nchildsChild.info('hello baby..')\n\npino.debug('this should be mute')\n\npino.level = 'trace'\n\npino.debug('this is a debug statement')\n\npino.child({ another: 'property' }).debug('this is a debug statement via child')\npino.trace('this is a trace statement')\n\npino.debug('this is a \"debug\" statement with \"')\n\npino.info(new Error('kaboom'))\npino.info(null)\n\npino.info(new Error('kaboom'), 'with', 'a', 'message')\n"
  },
  {
    "path": "examples/transport.js",
    "content": "'use strict'\n\nconst pino = require('..')\nconst { tmpdir } = require('node:os')\nconst { join } = require('node:path')\n\nconst file = join(tmpdir(), `pino-${process.pid}-example`)\n\nconst transport = pino.transport({\n  targets: [{\n    level: 'warn',\n    target: 'pino/file',\n    options: {\n      destination: file\n    }\n    /*\n  }, {\n    level: 'info',\n    target: 'pino-elasticsearch',\n    options: {\n      node: 'http://localhost:9200'\n    }\n    */\n  }, {\n    level: 'info',\n    target: 'pino-pretty'\n  }]\n})\n\nconst logger = pino(transport)\n\nlogger.info({\n  file\n}, 'logging destination')\n\nlogger.info('hello world')\nlogger.error('this is at error level')\nlogger.info('the answer is %d', 42)\nlogger.info({ obj: 42 }, 'hello world')\nlogger.info({ obj: 42, b: 2 }, 'hello world')\nlogger.info({ nested: { obj: 42 } }, 'nested')\nlogger.warn('WARNING!')\nsetImmediate(() => {\n  logger.info('after setImmediate')\n})\nlogger.error(new Error('an error'))\n\nconst child = logger.child({ a: 'property' })\nchild.info('hello child!')\n\nconst childsChild = child.child({ another: 'property' })\nchildsChild.info('hello baby..')\n\nlogger.debug('this should be mute')\n\nlogger.level = 'trace'\n\nlogger.debug('this is a debug statement')\n\nlogger.child({ another: 'property' }).debug('this is a debug statement via child')\nlogger.trace('this is a trace statement')\n\nlogger.debug('this is a \"debug\" statement with \"')\n\nlogger.info(new Error('kaboom'))\nlogger.info(null)\n\nlogger.info(new Error('kaboom'), 'with', 'a', 'message')\n"
  },
  {
    "path": "file.js",
    "content": "'use strict'\n\nconst pino = require('./pino')\nconst { once } = require('node:events')\n\nmodule.exports = async function (opts = {}) {\n  const destOpts = Object.assign({}, opts, { dest: opts.destination || 1, sync: false })\n  delete destOpts.destination\n  const destination = pino.destination(destOpts)\n  await once(destination, 'ready')\n  return destination\n}\n"
  },
  {
    "path": "inc-version.sh",
    "content": "#!/bin/bash \n\nset -e\n\nPATH=./node_modules/.bin:${PATH}\nCURRENT_VERSION=$(jq -r .version package.json)\n\ncase ${1} in\n  Major | MAJOR | major)\n    LEVEL=major\n    ;;\n\n  Minor | MINOR | minor)\n    LEVEL=minor\n    ;;\n\n  Patch | PATCH | patch)\n    LEVEL=patch\n    ;;\n\n  *)\n    LEVEL=patch\n    ;;\nesac\n\nNEW_VERSION=$(semver -i ${LEVEL} ${CURRENT_VERSION})\necho \"${CURRENT_VERSION} => ${NEW_VERSION}\"\nread -n 1 -s -r -p \"Press any key to continue (ctrl+c to abort)...\"\necho \"\"\n\necho \"Patching package.json...\"\ncat package.json | \\\n  jq --arg vers \"${NEW_VERSION}\" '.version = $vers' | \\\n  tee package.json 1>/dev/null\n\necho \"Patching lib/meta.js ...\"\nSED_SCRIPT=$(printf 's/%s/%s/' ${CURRENT_VERSION//\\./\\\\.} ${NEW_VERSION//\\./\\\\.})\ncat ./lib/meta.js | \\\n  sed -e ${SED_SCRIPT} | \\\n  tee ./lib/meta.js 1>/dev/null\n\necho \"Done.\"\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Pino - Super fast, all natural JSON logger for Node.js</title>\n  <meta name=\"description\" content=\"Super fast, all natural JSON logger for Node.js\">\n  <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n  <link rel=\"stylesheet\" href=\"//unpkg.com/docsify-themeable/dist/css/theme-simple.css\">\n  <style>\n    :root {\n      --base-font-size: 16px;\n      --theme-color: rgb(104, 118, 52);\n      --link-color:  rgb(104, 118, 52);\n      --link-color--hover: rgb(137, 152, 100);\n      --sidebar-name-margin: 0;\n      --sidebar-name-padding: 0;\n      --code-font-size: .9em;\n    }\n    .sidebar > h1 {\n      margin-bottom: -.75em;\n      margin-top: .75em;\n    }\n    .sidebar > h1 img {\n      height: 4em;\n    }\n    .markdown-section a code {\n      color: var(--link-color)!important;\n    }\n    .markdown-section code:not([class*=\"lang-\"]):not([class*=\"language-\"]) {\n      white-space: unset\n    }\n  </style>\n  <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"favicon-32x32.png\">\n  <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"favicon-16x16.png\">\n</head>\n<body>\n  <div id=\"app\"></div>\n</body>\n<script>\n  window.$docsify = {\n    name: 'pino',\n    logo: './pino-tree.png',\n    loadSidebar: 'docsify/sidebar.md',\n    repo: 'https://github.com/pinojs/pino',\n    auto2top: true,\n    ga: 'UA-103155139-1'\n  }\n</script>\n<script src=\"//unpkg.com/docsify/lib/docsify.min.js\"></script>\n<script src=\"//unpkg.com/docsify/lib/plugins/search.min.js\"></script>\n<script src=\"//unpkg.com/docsify/lib/plugins/ga.min.js\"></script>\n<!-- To enable syntax highlighting on TypeScript codes: -->\n<script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-typescript.min.js\"></script>\n\n</html>\n"
  },
  {
    "path": "lib/caller.js",
    "content": "'use strict'\n\nfunction noOpPrepareStackTrace (_, stack) {\n  return stack\n}\n\nmodule.exports = function getCallers () {\n  const originalPrepare = Error.prepareStackTrace\n  Error.prepareStackTrace = noOpPrepareStackTrace\n  const stack = new Error().stack\n  Error.prepareStackTrace = originalPrepare\n\n  if (!Array.isArray(stack)) {\n    return undefined\n  }\n\n  const entries = stack.slice(2)\n\n  const fileNames = []\n\n  for (const entry of entries) {\n    if (!entry) {\n      continue\n    }\n\n    fileNames.push(entry.getFileName())\n  }\n\n  return fileNames\n}\n"
  },
  {
    "path": "lib/constants.js",
    "content": "/**\n * Represents default log level values\n *\n * @enum {number}\n */\nconst DEFAULT_LEVELS = {\n  trace: 10,\n  debug: 20,\n  info: 30,\n  warn: 40,\n  error: 50,\n  fatal: 60\n}\n\n/**\n * Represents sort order direction: `ascending` or `descending`\n *\n * @enum {string}\n */\nconst SORTING_ORDER = {\n  ASC: 'ASC',\n  DESC: 'DESC'\n}\n\nmodule.exports = {\n  DEFAULT_LEVELS,\n  SORTING_ORDER\n}\n"
  },
  {
    "path": "lib/deprecations.js",
    "content": "'use strict'\n\nconst warning = require('process-warning')()\nmodule.exports = warning\n\n// const warnName = 'PinoWarning'\n\n// warning.create(warnName, 'PINODEP010', 'A new deprecation')\n"
  },
  {
    "path": "lib/levels.js",
    "content": "'use strict'\n/* eslint no-prototype-builtins: 0 */\nconst {\n  lsCacheSym,\n  levelValSym,\n  useOnlyCustomLevelsSym,\n  streamSym,\n  formattersSym,\n  hooksSym,\n  levelCompSym\n} = require('./symbols')\nconst { noop, genLog } = require('./tools')\nconst { DEFAULT_LEVELS, SORTING_ORDER } = require('./constants')\n\nconst levelMethods = {\n  fatal: (hook) => {\n    const logFatal = genLog(DEFAULT_LEVELS.fatal, hook)\n    return function (...args) {\n      const stream = this[streamSym]\n      logFatal.call(this, ...args)\n      if (typeof stream.flushSync === 'function') {\n        try {\n          stream.flushSync()\n        } catch (e) {\n          // https://github.com/pinojs/pino/pull/740#discussion_r346788313\n        }\n      }\n    }\n  },\n  error: (hook) => genLog(DEFAULT_LEVELS.error, hook),\n  warn: (hook) => genLog(DEFAULT_LEVELS.warn, hook),\n  info: (hook) => genLog(DEFAULT_LEVELS.info, hook),\n  debug: (hook) => genLog(DEFAULT_LEVELS.debug, hook),\n  trace: (hook) => genLog(DEFAULT_LEVELS.trace, hook)\n}\n\nconst nums = Object.keys(DEFAULT_LEVELS).reduce((o, k) => {\n  o[DEFAULT_LEVELS[k]] = k\n  return o\n}, {})\n\nconst initialLsCache = Object.keys(nums).reduce((o, k) => {\n  o[k] = '{\"level\":' + Number(k)\n  return o\n}, {})\n\nfunction genLsCache (instance) {\n  const formatter = instance[formattersSym].level\n  const { labels } = instance.levels\n  const cache = {}\n  for (const label in labels) {\n    const level = formatter(labels[label], Number(label))\n    cache[label] = JSON.stringify(level).slice(0, -1)\n  }\n  instance[lsCacheSym] = cache\n  return instance\n}\n\nfunction isStandardLevel (level, useOnlyCustomLevels) {\n  if (useOnlyCustomLevels) {\n    return false\n  }\n\n  switch (level) {\n    case 'fatal':\n    case 'error':\n    case 'warn':\n    case 'info':\n    case 'debug':\n    case 'trace':\n      return true\n    default:\n      return false\n  }\n}\n\nfunction setLevel (level) {\n  const { labels, values } = this.levels\n  if (typeof level === 'number') {\n    if (labels[level] === undefined) throw Error('unknown level value' + level)\n    level = labels[level]\n  }\n  if (values[level] === undefined) throw Error('unknown level ' + level)\n  const preLevelVal = this[levelValSym]\n  const levelVal = this[levelValSym] = values[level]\n  const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]\n  const levelComparison = this[levelCompSym]\n  const hook = this[hooksSym].logMethod\n\n  for (const key in values) {\n    if (levelComparison(values[key], levelVal) === false) {\n      this[key] = noop\n      continue\n    }\n    this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook)\n  }\n\n  this.emit(\n    'level-change',\n    level,\n    levelVal,\n    labels[preLevelVal],\n    preLevelVal,\n    this\n  )\n}\n\nfunction getLevel (level) {\n  const { levels, levelVal } = this\n  // protection against potential loss of Pino scope from serializers (edge case with circular refs - https://github.com/pinojs/pino/issues/833)\n  return (levels && levels.labels) ? levels.labels[levelVal] : ''\n}\n\nfunction isLevelEnabled (logLevel) {\n  const { values } = this.levels\n  const logLevelVal = values[logLevel]\n  return logLevelVal !== undefined && this[levelCompSym](logLevelVal, this[levelValSym])\n}\n\n/**\n * Determine if the given `current` level is enabled by comparing it\n * against the current threshold (`expected`).\n *\n * @param {SORTING_ORDER} direction comparison direction \"ASC\" or \"DESC\"\n * @param {number} current current log level number representation\n * @param {number} expected threshold value to compare with\n * @returns {boolean}\n */\nfunction compareLevel (direction, current, expected) {\n  if (direction === SORTING_ORDER.DESC) {\n    return current <= expected\n  }\n\n  return current >= expected\n}\n\n/**\n * Create a level comparison function based on `levelComparison`\n * it could a default function which compares levels either in \"ascending\" or \"descending\" order or custom comparison function\n *\n * @param {SORTING_ORDER | Function} levelComparison sort levels order direction or custom comparison function\n * @returns Function\n */\nfunction genLevelComparison (levelComparison) {\n  if (typeof levelComparison === 'string') {\n    return compareLevel.bind(null, levelComparison)\n  }\n\n  return levelComparison\n}\n\nfunction mappings (customLevels = null, useOnlyCustomLevels = false) {\n  const customNums = customLevels\n    /* eslint-disable */\n    ? Object.keys(customLevels).reduce((o, k) => {\n        o[customLevels[k]] = k\n        return o\n      }, {})\n    : null\n    /* eslint-enable */\n\n  const labels = Object.assign(\n    Object.create(Object.prototype, { Infinity: { value: 'silent' } }),\n    useOnlyCustomLevels ? null : nums,\n    customNums\n  )\n  const values = Object.assign(\n    Object.create(Object.prototype, { silent: { value: Infinity } }),\n    useOnlyCustomLevels ? null : DEFAULT_LEVELS,\n    customLevels\n  )\n  return { labels, values }\n}\n\nfunction assertDefaultLevelFound (defaultLevel, customLevels, useOnlyCustomLevels) {\n  if (typeof defaultLevel === 'number') {\n    const values = [].concat(\n      Object.keys(customLevels || {}).map(key => customLevels[key]),\n      useOnlyCustomLevels ? [] : Object.keys(nums).map(level => +level),\n      Infinity\n    )\n    if (!values.includes(defaultLevel)) {\n      throw Error(`default level:${defaultLevel} must be included in custom levels`)\n    }\n    return\n  }\n\n  const labels = Object.assign(\n    Object.create(Object.prototype, { silent: { value: Infinity } }),\n    useOnlyCustomLevels ? null : DEFAULT_LEVELS,\n    customLevels\n  )\n  if (!(defaultLevel in labels)) {\n    throw Error(`default level:${defaultLevel} must be included in custom levels`)\n  }\n}\n\nfunction assertNoLevelCollisions (levels, customLevels) {\n  const { labels, values } = levels\n  for (const k in customLevels) {\n    if (k in values) {\n      throw Error('levels cannot be overridden')\n    }\n    if (customLevels[k] in labels) {\n      throw Error('pre-existing level values cannot be used for new levels')\n    }\n  }\n}\n\n/**\n * Validates whether `levelComparison` is correct\n *\n * @throws Error\n * @param {SORTING_ORDER | Function} levelComparison - value to validate\n * @returns\n */\nfunction assertLevelComparison (levelComparison) {\n  if (typeof levelComparison === 'function') {\n    return\n  }\n\n  if (typeof levelComparison === 'string' && Object.values(SORTING_ORDER).includes(levelComparison)) {\n    return\n  }\n\n  throw new Error('Levels comparison should be one of \"ASC\", \"DESC\" or \"function\" type')\n}\n\nmodule.exports = {\n  initialLsCache,\n  genLsCache,\n  levelMethods,\n  getLevel,\n  setLevel,\n  isLevelEnabled,\n  mappings,\n  assertNoLevelCollisions,\n  assertDefaultLevelFound,\n  genLevelComparison,\n  assertLevelComparison\n}\n"
  },
  {
    "path": "lib/meta.js",
    "content": "'use strict'\n\nmodule.exports = { version: '10.3.1' }\n"
  },
  {
    "path": "lib/multistream.js",
    "content": "'use strict'\n\nconst metadata = Symbol.for('pino.metadata')\nconst { DEFAULT_LEVELS } = require('./constants')\n\nconst DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info\n\nfunction multistream (streamsArray, opts) {\n  streamsArray = streamsArray || []\n  opts = opts || { dedupe: false }\n\n  const streamLevels = Object.create(DEFAULT_LEVELS)\n  streamLevels.silent = Infinity\n  if (opts.levels && typeof opts.levels === 'object') {\n    Object.keys(opts.levels).forEach(i => {\n      streamLevels[i] = opts.levels[i]\n    })\n  }\n\n  const res = {\n    write,\n    add,\n    remove,\n    emit,\n    flushSync,\n    end,\n    minLevel: 0,\n    lastId: 0,\n    streams: [],\n    clone,\n    [metadata]: true,\n    streamLevels\n  }\n\n  if (Array.isArray(streamsArray)) {\n    streamsArray.forEach(add, res)\n  } else {\n    add.call(res, streamsArray)\n  }\n\n  // clean this object up\n  // or it will stay allocated forever\n  // as it is closed on the following closures\n  streamsArray = null\n\n  return res\n\n  // we can exit early because the streams are ordered by level\n  function write (data) {\n    let dest\n    const level = this.lastLevel\n    const { streams } = this\n    // for handling situation when several streams has the same level\n    let recordedLevel = 0\n    let stream\n\n    // if dedupe set to true we send logs to the stream with the highest level\n    // therefore, we have to change sorting order\n    for (let i = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i, streams.length, opts.dedupe); i = adjustLoopVar(i, opts.dedupe)) {\n      dest = streams[i]\n      if (dest.level <= level) {\n        if (recordedLevel !== 0 && recordedLevel !== dest.level) {\n          break\n        }\n        stream = dest.stream\n        if (stream[metadata]) {\n          const { lastTime, lastMsg, lastObj, lastLogger } = this\n          stream.lastLevel = level\n          stream.lastTime = lastTime\n          stream.lastMsg = lastMsg\n          stream.lastObj = lastObj\n          stream.lastLogger = lastLogger\n        }\n        stream.write(data)\n        if (opts.dedupe) {\n          recordedLevel = dest.level\n        }\n      } else if (!opts.dedupe) {\n        break\n      }\n    }\n  }\n\n  function emit (...args) {\n    for (const { stream } of this.streams) {\n      if (typeof stream.emit === 'function') {\n        stream.emit(...args)\n      }\n    }\n  }\n\n  function flushSync () {\n    for (const { stream } of this.streams) {\n      if (typeof stream.flushSync === 'function') {\n        stream.flushSync()\n      }\n    }\n  }\n\n  function add (dest) {\n    if (!dest) {\n      return res\n    }\n\n    // Check that dest implements either StreamEntry or DestinationStream\n    const isStream = typeof dest.write === 'function' || dest.stream\n    const stream_ = dest.write ? dest : dest.stream\n    // This is necessary to provide a meaningful error message, otherwise it throws somewhere inside write()\n    if (!isStream) {\n      throw Error('stream object needs to implement either StreamEntry or DestinationStream interface')\n    }\n\n    const { streams, streamLevels } = this\n\n    let level\n    if (typeof dest.levelVal === 'number') {\n      level = dest.levelVal\n    } else if (typeof dest.level === 'string') {\n      level = streamLevels[dest.level]\n    } else if (typeof dest.level === 'number') {\n      level = dest.level\n    } else {\n      level = DEFAULT_INFO_LEVEL\n    }\n\n    const dest_ = {\n      stream: stream_,\n      level,\n      levelVal: undefined,\n      id: ++res.lastId\n    }\n\n    streams.unshift(dest_)\n    streams.sort(compareByLevel)\n\n    this.minLevel = streams[0].level\n\n    return res\n  }\n\n  function remove (id) {\n    const { streams } = this\n    const index = streams.findIndex(s => s.id === id)\n\n    if (index >= 0) {\n      streams.splice(index, 1)\n      streams.sort(compareByLevel)\n      this.minLevel = streams.length > 0 ? streams[0].level : -1\n    }\n\n    return res\n  }\n\n  function end () {\n    for (const { stream } of this.streams) {\n      if (typeof stream.flushSync === 'function') {\n        stream.flushSync()\n      }\n      stream.end()\n    }\n  }\n\n  function clone (level) {\n    const streams = new Array(this.streams.length)\n\n    for (let i = 0; i < streams.length; i++) {\n      streams[i] = {\n        level,\n        stream: this.streams[i].stream\n      }\n    }\n\n    return {\n      write,\n      add,\n      remove,\n      minLevel: level,\n      streams,\n      clone,\n      emit,\n      flushSync,\n      [metadata]: true\n    }\n  }\n}\n\nfunction compareByLevel (a, b) {\n  return a.level - b.level\n}\n\nfunction initLoopVar (length, dedupe) {\n  return dedupe ? length - 1 : 0\n}\n\nfunction adjustLoopVar (i, dedupe) {\n  return dedupe ? i - 1 : i + 1\n}\n\nfunction checkLoopVar (i, length, dedupe) {\n  return dedupe ? i >= 0 : i < length\n}\n\nmodule.exports = multistream\n"
  },
  {
    "path": "lib/proto.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst { EventEmitter } = require('node:events')\nconst {\n  lsCacheSym,\n  levelValSym,\n  setLevelSym,\n  getLevelSym,\n  chindingsSym,\n  mixinSym,\n  asJsonSym,\n  writeSym,\n  mixinMergeStrategySym,\n  timeSym,\n  timeSliceIndexSym,\n  streamSym,\n  serializersSym,\n  formattersSym,\n  errorKeySym,\n  messageKeySym,\n  useOnlyCustomLevelsSym,\n  needsMetadataGsym,\n  redactFmtSym,\n  stringifySym,\n  formatOptsSym,\n  stringifiersSym,\n  msgPrefixSym,\n  hooksSym\n} = require('./symbols')\nconst {\n  getLevel,\n  setLevel,\n  isLevelEnabled,\n  mappings,\n  initialLsCache,\n  genLsCache,\n  assertNoLevelCollisions\n} = require('./levels')\nconst {\n  asChindings,\n  asJson,\n  buildFormatters,\n  stringify,\n  noop\n} = require('./tools')\nconst {\n  version\n} = require('./meta')\nconst redaction = require('./redaction')\n\n// note: use of class is satirical\n// https://github.com/pinojs/pino/pull/433#pullrequestreview-127703127\nconst constructor = class Pino {}\nconst prototype = {\n  constructor,\n  child,\n  bindings,\n  setBindings,\n  flush,\n  isLevelEnabled,\n  version,\n  get level () { return this[getLevelSym]() },\n  set level (lvl) { this[setLevelSym](lvl) },\n  get levelVal () { return this[levelValSym] },\n  set levelVal (n) { throw Error('levelVal is read-only') },\n  get msgPrefix () { return this[msgPrefixSym] },\n  get [Symbol.toStringTag] () { return 'Pino' },\n  [lsCacheSym]: initialLsCache,\n  [writeSym]: write,\n  [asJsonSym]: asJson,\n  [getLevelSym]: getLevel,\n  [setLevelSym]: setLevel\n}\n\nObject.setPrototypeOf(prototype, EventEmitter.prototype)\n\n// exporting and consuming the prototype object using factory pattern fixes scoping issues with getters when serializing\nmodule.exports = function () {\n  return Object.create(prototype)\n}\n\nconst resetChildingsFormatter = bindings => bindings\nfunction child (bindings, options) {\n  if (!bindings) {\n    throw Error('missing bindings for child Pino')\n  }\n  const serializers = this[serializersSym]\n  const formatters = this[formattersSym]\n  const instance = Object.create(this)\n\n  // If an `options` object was not supplied, we can improve\n  // the performance of child creation by skipping\n  // the checks for set options and simply return\n  // a baseline instance.\n  if (options == null) {\n    if (instance[formattersSym].bindings !== resetChildingsFormatter) {\n      instance[formattersSym] = buildFormatters(\n        formatters.level,\n        resetChildingsFormatter,\n        formatters.log\n      )\n    }\n\n    instance[chindingsSym] = asChindings(instance, bindings)\n\n    if (this.onChild !== noop) {\n      this.onChild(instance)\n    }\n\n    return instance\n  }\n\n  if (options.hasOwnProperty('serializers') === true) {\n    instance[serializersSym] = Object.create(null)\n\n    for (const k in serializers) {\n      instance[serializersSym][k] = serializers[k]\n    }\n    const parentSymbols = Object.getOwnPropertySymbols(serializers)\n    /* eslint no-var: off */\n    for (var i = 0; i < parentSymbols.length; i++) {\n      const ks = parentSymbols[i]\n      instance[serializersSym][ks] = serializers[ks]\n    }\n\n    for (const bk in options.serializers) {\n      instance[serializersSym][bk] = options.serializers[bk]\n    }\n    const bindingsSymbols = Object.getOwnPropertySymbols(options.serializers)\n    for (var bi = 0; bi < bindingsSymbols.length; bi++) {\n      const bks = bindingsSymbols[bi]\n      instance[serializersSym][bks] = options.serializers[bks]\n    }\n  } else instance[serializersSym] = serializers\n  if (options.hasOwnProperty('formatters')) {\n    const { level, bindings: chindings, log } = options.formatters\n    instance[formattersSym] = buildFormatters(\n      level || formatters.level,\n      chindings || resetChildingsFormatter,\n      log || formatters.log\n    )\n  } else {\n    instance[formattersSym] = buildFormatters(\n      formatters.level,\n      resetChildingsFormatter,\n      formatters.log\n    )\n  }\n  if (options.hasOwnProperty('customLevels') === true) {\n    assertNoLevelCollisions(this.levels, options.customLevels)\n    instance.levels = mappings(options.customLevels, instance[useOnlyCustomLevelsSym])\n    genLsCache(instance)\n  }\n\n  // redact must place before asChindings and only replace if exist\n  if ((typeof options.redact === 'object' && options.redact !== null) || Array.isArray(options.redact)) {\n    instance.redact = options.redact // replace redact directly\n    const stringifiers = redaction(instance.redact, stringify)\n    const formatOpts = { stringify: stringifiers[redactFmtSym] }\n    instance[stringifySym] = stringify\n    instance[stringifiersSym] = stringifiers\n    instance[formatOptsSym] = formatOpts\n  }\n\n  if (typeof options.msgPrefix === 'string') {\n    instance[msgPrefixSym] = (this[msgPrefixSym] || '') + options.msgPrefix\n  }\n\n  instance[chindingsSym] = asChindings(instance, bindings)\n  if ((options.level !== undefined && options.level !== this.level) || options.hasOwnProperty('customLevels')) {\n    const childLevel = options.level || this.level\n    instance[setLevelSym](childLevel)\n  }\n  this.onChild(instance)\n  return instance\n}\n\nfunction bindings () {\n  const chindings = this[chindingsSym]\n  const chindingsJson = `{${chindings.substr(1)}}` // at least contains ,\"pid\":7068,\"hostname\":\"myMac\"\n  const bindingsFromJson = JSON.parse(chindingsJson)\n  delete bindingsFromJson.pid\n  delete bindingsFromJson.hostname\n  return bindingsFromJson\n}\n\nfunction setBindings (newBindings) {\n  const chindings = asChindings(this, newBindings)\n  this[chindingsSym] = chindings\n}\n\n/**\n * Default strategy for creating `mergeObject` from arguments and the result from `mixin()`.\n * Fields from `mergeObject` have higher priority in this strategy.\n *\n * @param {Object} mergeObject The object a user has supplied to the logging function.\n * @param {Object} mixinObject The result of the `mixin` method.\n * @return {Object}\n */\nfunction defaultMixinMergeStrategy (mergeObject, mixinObject) {\n  return Object.assign(mixinObject, mergeObject)\n}\n\nfunction write (_obj, msg, num) {\n  const t = this[timeSym]()\n  const mixin = this[mixinSym]\n  const errorKey = this[errorKeySym]\n  const messageKey = this[messageKeySym]\n  const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy\n  let obj\n  const streamWriteHook = this[hooksSym].streamWrite\n\n  if (_obj === undefined || _obj === null) {\n    obj = {}\n  } else if (_obj instanceof Error) {\n    obj = { [errorKey]: _obj }\n    if (msg === undefined) {\n      msg = _obj.message\n    }\n  } else {\n    obj = _obj\n    if (msg === undefined && _obj[messageKey] === undefined && _obj[errorKey]) {\n      msg = _obj[errorKey].message\n    }\n  }\n\n  if (mixin) {\n    obj = mixinMergeStrategy(obj, mixin(obj, num, this))\n  }\n\n  const s = this[asJsonSym](obj, msg, num, t)\n\n  const stream = this[streamSym]\n  if (stream[needsMetadataGsym] === true) {\n    stream.lastLevel = num\n    stream.lastObj = obj\n    stream.lastMsg = msg\n    stream.lastTime = t.slice(this[timeSliceIndexSym])\n    stream.lastLogger = this // for child loggers\n  }\n  stream.write(streamWriteHook ? streamWriteHook(s) : s)\n}\n\nfunction flush (cb) {\n  if (cb != null && typeof cb !== 'function') {\n    throw Error('callback must be a function')\n  }\n\n  const stream = this[streamSym]\n\n  if (typeof stream.flush === 'function') {\n    stream.flush(cb || noop)\n  } else if (cb) cb()\n}\n"
  },
  {
    "path": "lib/redaction.js",
    "content": "'use strict'\n\nconst Redact = require('@pinojs/redact')\nconst { redactFmtSym, wildcardFirstSym } = require('./symbols')\n\n// Custom rx regex equivalent to fast-redact's rx\nconst rx = /[^.[\\]]+|\\[([^[\\]]*?)\\]/g\n\nconst CENSOR = '[Redacted]'\nconst strict = false // TODO should this be configurable?\n\nfunction redaction (opts, serialize) {\n  const { paths, censor, remove } = handle(opts)\n\n  const shape = paths.reduce((o, str) => {\n    rx.lastIndex = 0\n    const first = rx.exec(str)\n    const next = rx.exec(str)\n\n    // ns is the top-level path segment, brackets + quoting removed.\n    let ns = first[1] !== undefined\n      ? first[1].replace(/^(?:\"|'|`)(.*)(?:\"|'|`)$/, '$1')\n      : first[0]\n\n    if (ns === '*') {\n      ns = wildcardFirstSym\n    }\n\n    // top level key:\n    if (next === null) {\n      o[ns] = null\n      return o\n    }\n\n    // path with at least two segments:\n    // if ns is already redacted at the top level, ignore lower level redactions\n    if (o[ns] === null) {\n      return o\n    }\n\n    const { index } = next\n    const nextPath = `${str.substr(index, str.length - 1)}`\n\n    o[ns] = o[ns] || []\n\n    // shape is a mix of paths beginning with literal values and wildcard\n    // paths [ \"a.b.c\", \"*.b.z\" ] should reduce to a shape of\n    // { \"a\": [ \"b.c\", \"b.z\" ], *: [ \"b.z\" ] }\n    // note: \"b.z\" is in both \"a\" and * arrays because \"a\" matches the wildcard.\n    // (* entry has wildcardFirstSym as key)\n    if (ns !== wildcardFirstSym && o[ns].length === 0) {\n      // first time ns's get all '*' redactions so far\n      o[ns].push(...(o[wildcardFirstSym] || []))\n    }\n\n    if (ns === wildcardFirstSym) {\n      // new * path gets added to all previously registered literal ns's.\n      Object.keys(o).forEach(function (k) {\n        if (o[k]) {\n          o[k].push(nextPath)\n        }\n      })\n    }\n\n    o[ns].push(nextPath)\n    return o\n  }, {})\n\n  // the redactor assigned to the format symbol key\n  // provides top level redaction for instances where\n  // an object is interpolated into the msg string\n  const result = {\n    [redactFmtSym]: Redact({ paths, censor, serialize, strict, remove })\n  }\n\n  const topCensor = (...args) => {\n    return typeof censor === 'function' ? serialize(censor(...args)) : serialize(censor)\n  }\n\n  return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o, k) => {\n    // top level key:\n    if (shape[k] === null) {\n      o[k] = (value) => topCensor(value, [k])\n    } else {\n      const wrappedCensor = typeof censor === 'function'\n        ? (value, path) => {\n            return censor(value, [k, ...path])\n          }\n        : censor\n      o[k] = Redact({\n        paths: shape[k],\n        censor: wrappedCensor,\n        serialize,\n        strict,\n        remove\n      })\n    }\n    return o\n  }, result)\n}\n\nfunction handle (opts) {\n  if (Array.isArray(opts)) {\n    opts = { paths: opts, censor: CENSOR }\n    return opts\n  }\n  let { paths, censor = CENSOR, remove } = opts\n  if (Array.isArray(paths) === false) { throw Error('pino – redact must contain an array of strings') }\n  if (remove === true) censor = undefined\n\n  return { paths, censor, remove }\n}\n\nmodule.exports = redaction\n"
  },
  {
    "path": "lib/symbols.js",
    "content": "'use strict'\n\nconst setLevelSym = Symbol('pino.setLevel')\nconst getLevelSym = Symbol('pino.getLevel')\nconst levelValSym = Symbol('pino.levelVal')\nconst levelCompSym = Symbol('pino.levelComp')\nconst useLevelLabelsSym = Symbol('pino.useLevelLabels')\nconst useOnlyCustomLevelsSym = Symbol('pino.useOnlyCustomLevels')\nconst mixinSym = Symbol('pino.mixin')\n\nconst lsCacheSym = Symbol('pino.lsCache')\nconst chindingsSym = Symbol('pino.chindings')\n\nconst asJsonSym = Symbol('pino.asJson')\nconst writeSym = Symbol('pino.write')\nconst redactFmtSym = Symbol('pino.redactFmt')\n\nconst timeSym = Symbol('pino.time')\nconst timeSliceIndexSym = Symbol('pino.timeSliceIndex')\nconst streamSym = Symbol('pino.stream')\nconst stringifySym = Symbol('pino.stringify')\nconst stringifySafeSym = Symbol('pino.stringifySafe')\nconst stringifiersSym = Symbol('pino.stringifiers')\nconst endSym = Symbol('pino.end')\nconst formatOptsSym = Symbol('pino.formatOpts')\nconst messageKeySym = Symbol('pino.messageKey')\nconst errorKeySym = Symbol('pino.errorKey')\nconst nestedKeySym = Symbol('pino.nestedKey')\nconst nestedKeyStrSym = Symbol('pino.nestedKeyStr')\nconst mixinMergeStrategySym = Symbol('pino.mixinMergeStrategy')\nconst msgPrefixSym = Symbol('pino.msgPrefix')\n\nconst wildcardFirstSym = Symbol('pino.wildcardFirst')\n\n// public symbols, no need to use the same pino\n// version for these\nconst serializersSym = Symbol.for('pino.serializers')\nconst formattersSym = Symbol.for('pino.formatters')\nconst hooksSym = Symbol.for('pino.hooks')\nconst needsMetadataGsym = Symbol.for('pino.metadata')\nconst transportUsesMultistreamSym = Symbol.for('pino.transport.usesMultistream')\n\nmodule.exports = {\n  setLevelSym,\n  getLevelSym,\n  levelValSym,\n  levelCompSym,\n  useLevelLabelsSym,\n  mixinSym,\n  lsCacheSym,\n  chindingsSym,\n  asJsonSym,\n  writeSym,\n  serializersSym,\n  redactFmtSym,\n  timeSym,\n  timeSliceIndexSym,\n  streamSym,\n  stringifySym,\n  stringifySafeSym,\n  stringifiersSym,\n  endSym,\n  formatOptsSym,\n  messageKeySym,\n  errorKeySym,\n  nestedKeySym,\n  wildcardFirstSym,\n  needsMetadataGsym,\n  useOnlyCustomLevelsSym,\n  formattersSym,\n  hooksSym,\n  nestedKeyStrSym,\n  mixinMergeStrategySym,\n  msgPrefixSym,\n  transportUsesMultistreamSym\n}\n"
  },
  {
    "path": "lib/time.js",
    "content": "'use strict'\n\nconst nullTime = () => ''\n\nconst epochTime = () => `,\"time\":${Date.now()}`\n\nconst unixTime = () => `,\"time\":${Math.round(Date.now() / 1000.0)}`\n\nconst isoTime = () => `,\"time\":\"${new Date(Date.now()).toISOString()}\"` // using Date.now() for testability\n\nconst NS_PER_MS = 1_000_000n\nconst NS_PER_SEC = 1_000_000_000n\n\nconst startWallTimeNs = BigInt(Date.now()) * NS_PER_MS\nconst startHrTime = process.hrtime.bigint()\n\nconst isoTimeNano = () => {\n  const elapsedNs = process.hrtime.bigint() - startHrTime\n  const currentTimeNs = startWallTimeNs + elapsedNs\n\n  const secondsSinceEpoch = currentTimeNs / NS_PER_SEC\n  const nanosWithinSecond = currentTimeNs % NS_PER_SEC\n\n  const msSinceEpoch = Number(secondsSinceEpoch * 1000n + nanosWithinSecond / 1_000_000n)\n  const date = new Date(msSinceEpoch)\n\n  const year = date.getUTCFullYear()\n  const month = (date.getUTCMonth() + 1).toString().padStart(2, '0')\n  const day = date.getUTCDate().toString().padStart(2, '0')\n  const hours = date.getUTCHours().toString().padStart(2, '0')\n  const minutes = date.getUTCMinutes().toString().padStart(2, '0')\n  const seconds = date.getUTCSeconds().toString().padStart(2, '0')\n\n  return `,\"time\":\"${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${nanosWithinSecond\n    .toString()\n    .padStart(9, '0')}Z\"`\n}\n\nmodule.exports = { nullTime, epochTime, unixTime, isoTime, isoTimeNano }\n"
  },
  {
    "path": "lib/tools.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst diagChan = require('node:diagnostics_channel')\nconst format = require('quick-format-unescaped')\nconst { mapHttpRequest, mapHttpResponse } = require('pino-std-serializers')\nconst SonicBoom = require('sonic-boom')\nconst onExit = require('on-exit-leak-free')\nconst {\n  lsCacheSym,\n  chindingsSym,\n  writeSym,\n  serializersSym,\n  formatOptsSym,\n  endSym,\n  stringifiersSym,\n  stringifySym,\n  stringifySafeSym,\n  wildcardFirstSym,\n  nestedKeySym,\n  formattersSym,\n  messageKeySym,\n  errorKeySym,\n  nestedKeyStrSym,\n  msgPrefixSym\n} = require('./symbols')\nconst { isMainThread } = require('worker_threads')\nconst transport = require('./transport')\nconst [nodeMajor] = process.versions.node.split('.').map(v => Number(v))\n\nconst asJsonChan = diagChan.tracingChannel('pino_asJson')\n\n// JSON.stringify is faster in node 25+.\nconst asString = nodeMajor >= 25 ? str => JSON.stringify(str) : _asString\n\nfunction noop () {\n}\n\nfunction genLog (level, hook) {\n  if (!hook) return LOG\n\n  return function hookWrappedLog (...args) {\n    hook.call(this, args, LOG, level)\n  }\n\n  function LOG (o, ...n) {\n    if (typeof o === 'object') {\n      let msg = o\n      if (o !== null) {\n        if (o.method && o.headers && o.socket) {\n          o = mapHttpRequest(o)\n        } else if (typeof o.setHeader === 'function') {\n          o = mapHttpResponse(o)\n        }\n      }\n      let formatParams\n      if (msg === null && n.length === 0) {\n        formatParams = [null]\n      } else {\n        msg = n.shift()\n        formatParams = n\n      }\n      // We do not use a coercive check for `msg` as it is\n      // measurably slower than the explicit checks.\n      if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {\n        msg = this[msgPrefixSym] + msg\n      }\n      this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)\n    } else {\n      let msg = o === undefined ? n.shift() : o\n\n      // We do not use a coercive check for `msg` as it is\n      // measurably slower than the explicit checks.\n      if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {\n        msg = this[msgPrefixSym] + msg\n      }\n      this[writeSym](null, format(msg, n, this[formatOptsSym]), level)\n    }\n  }\n}\n\n// magically escape strings for json\n// relying on their charCodeAt\n// everything below 32 needs JSON.stringify()\n// 34 and 92 happens all the time, so we\n// have a fast case for them\nfunction _asString (str) {\n  let result = ''\n  let last = 0\n  let found = false\n  let point = 255\n  const l = str.length\n  if (l > 100) {\n    return JSON.stringify(str)\n  }\n  for (var i = 0; i < l && point >= 32; i++) {\n    point = str.charCodeAt(i)\n    if (point === 34 || point === 92) {\n      result += str.slice(last, i) + '\\\\'\n      last = i\n      found = true\n    }\n  }\n  if (!found) {\n    result = str\n  } else {\n    result += str.slice(last)\n  }\n  return point < 32 ? JSON.stringify(str) : '\"' + result + '\"'\n}\n\n/**\n * `asJson` wraps `_asJson` in order to facilitate generating diagnostics.\n *\n * @param {object} obj The merging object passed to the log method.\n * @param {string} msg The log message passed to the log method.\n * @param {number} num The log level number.\n * @param {number} time The log time in milliseconds.\n *\n * @returns {string}\n */\nfunction asJson (obj, msg, num, time) {\n  if (asJsonChan.hasSubscribers === false) {\n    return _asJson.call(this, obj, msg, num, time)\n  }\n\n  const store = { instance: this, arguments }\n  return asJsonChan.traceSync(_asJson, store, this, obj, msg, num, time)\n}\n\n/**\n * `_asJson` parses all collected data and generates the finalized newline\n * delimited JSON string.\n *\n * @param {object} obj The merging object passed to the log method.\n * @param {string} msg The log message passed to the log method.\n * @param {number} num The log level number.\n * @param {number} time The log time in milliseconds.\n *\n * @returns {string} The finalized log string terminated with a newline.\n * @private\n */\nfunction _asJson (obj, msg, num, time) {\n  const stringify = this[stringifySym]\n  const stringifySafe = this[stringifySafeSym]\n  const stringifiers = this[stringifiersSym]\n  const end = this[endSym]\n  const chindings = this[chindingsSym]\n  const serializers = this[serializersSym]\n  const formatters = this[formattersSym]\n  const messageKey = this[messageKeySym]\n  const errorKey = this[errorKeySym]\n  let data = this[lsCacheSym][num] + time\n\n  // we need the child bindings added to the output first so instance logged\n  // objects can take precedence when JSON.parse-ing the resulting log line\n  data = data + chindings\n\n  let value\n  if (formatters.log) {\n    obj = formatters.log(obj)\n  }\n  const wildcardStringifier = stringifiers[wildcardFirstSym]\n  let propStr = ''\n  for (const key in obj) {\n    value = obj[key]\n    if (Object.prototype.hasOwnProperty.call(obj, key) && value !== undefined) {\n      if (serializers[key]) {\n        value = serializers[key](value)\n      } else if (key === errorKey && serializers.err) {\n        value = serializers.err(value)\n      }\n\n      const stringifier = stringifiers[key] || wildcardStringifier\n\n      switch (typeof value) {\n        case 'undefined':\n        case 'function':\n          continue\n        case 'number':\n          /* eslint no-fallthrough: \"off\" */\n          if (Number.isFinite(value) === false) {\n            value = null\n          }\n        // this case explicitly falls through to the next one\n        case 'boolean':\n          if (stringifier) value = stringifier(value)\n          break\n        case 'string':\n          value = (stringifier || asString)(value)\n          break\n        default:\n          value = (stringifier || stringify)(value, stringifySafe)\n      }\n      if (value === undefined) continue\n      const strKey = asString(key)\n      propStr += ',' + strKey + ':' + value\n    }\n  }\n\n  let msgStr = ''\n  if (msg !== undefined) {\n    value = serializers[messageKey] ? serializers[messageKey](msg) : msg\n    const stringifier = stringifiers[messageKey] || wildcardStringifier\n\n    switch (typeof value) {\n      case 'function':\n        break\n      case 'number':\n        if (Number.isFinite(value) === false) {\n          value = null\n        }\n      // this case explicitly falls through to the next one\n      case 'boolean':\n        if (stringifier) value = stringifier(value)\n        msgStr = ',\"' + messageKey + '\":' + value\n        break\n      case 'string':\n        value = (stringifier || asString)(value)\n        msgStr = ',\"' + messageKey + '\":' + value\n        break\n      default:\n        value = (stringifier || stringify)(value, stringifySafe)\n        msgStr = ',\"' + messageKey + '\":' + value\n    }\n  }\n\n  if (this[nestedKeySym] && propStr) {\n    // place all the obj properties under the specified key\n    // the nested key is already formatted from the constructor\n    return data + this[nestedKeyStrSym] + propStr.slice(1) + '}' + msgStr + end\n  } else {\n    return data + propStr + msgStr + end\n  }\n}\n\nfunction asChindings (instance, bindings) {\n  let value\n  let data = instance[chindingsSym]\n  const stringify = instance[stringifySym]\n  const stringifySafe = instance[stringifySafeSym]\n  const stringifiers = instance[stringifiersSym]\n  const wildcardStringifier = stringifiers[wildcardFirstSym]\n  const serializers = instance[serializersSym]\n  const formatter = instance[formattersSym].bindings\n  bindings = formatter(bindings)\n\n  for (const key in bindings) {\n    value = bindings[key]\n    const valid = (key.length < 5 || (key !== 'level' &&\n      key !== 'serializers' &&\n      key !== 'formatters' &&\n      key !== 'customLevels')) &&\n      bindings.hasOwnProperty(key) &&\n      value !== undefined\n    if (valid === true) {\n      value = serializers[key] ? serializers[key](value) : value\n      value = (stringifiers[key] || wildcardStringifier || stringify)(value, stringifySafe)\n      if (value === undefined) continue\n      data += ',\"' + key + '\":' + value\n    }\n  }\n  return data\n}\n\nfunction hasBeenTampered (stream) {\n  return stream.write !== stream.constructor.prototype.write\n}\n\nfunction buildSafeSonicBoom (opts) {\n  const stream = new SonicBoom(opts)\n  stream.on('error', filterBrokenPipe)\n  // If we are sync: false, we must flush on exit\n  if (!opts.sync && isMainThread) {\n    onExit.register(stream, autoEnd)\n\n    stream.on('close', function () {\n      onExit.unregister(stream)\n    })\n  }\n  return stream\n\n  function filterBrokenPipe (err) {\n    // Impossible to replicate across all operating systems\n    /* istanbul ignore next */\n    if (err.code === 'EPIPE') {\n      // If we get EPIPE, we should stop logging here\n      // however we have no control to the consumer of\n      // SonicBoom, so we just overwrite the write method\n      stream.write = noop\n      stream.end = noop\n      stream.flushSync = noop\n      stream.destroy = noop\n      return\n    }\n    stream.removeListener('error', filterBrokenPipe)\n    stream.emit('error', err)\n  }\n}\n\nfunction autoEnd (stream, eventName) {\n  // This check is needed only on some platforms\n  /* istanbul ignore next */\n  if (stream.destroyed) {\n    return\n  }\n\n  if (eventName === 'beforeExit') {\n    // We still have an event loop, let's use it\n    stream.flush()\n    stream.on('drain', function () {\n      stream.end()\n    })\n  } else {\n    // For some reason istanbul is not detecting this, but it's there\n    /* istanbul ignore next */\n    // We do not have an event loop, so flush synchronously\n    stream.flushSync()\n  }\n}\n\nfunction createArgsNormalizer (defaultOptions) {\n  return function normalizeArgs (instance, caller, opts = {}, stream) {\n    // support stream as a string\n    if (typeof opts === 'string') {\n      stream = buildSafeSonicBoom({ dest: opts })\n      opts = {}\n    } else if (typeof stream === 'string') {\n      if (opts && opts.transport) {\n        throw Error('only one of option.transport or stream can be specified')\n      }\n      stream = buildSafeSonicBoom({ dest: stream })\n    } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {\n      stream = opts\n      opts = {}\n    } else if (opts.transport) {\n      if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {\n        throw Error('option.transport do not allow stream, please pass to option directly. e.g. pino(transport)')\n      }\n      if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') {\n        throw Error('option.transport.targets do not allow custom level formatters')\n      }\n\n      let customLevels\n      if (opts.customLevels) {\n        customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels)\n      }\n      stream = transport({ caller, ...opts.transport, levels: customLevels })\n    }\n    opts = Object.assign({}, defaultOptions, opts)\n    opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers)\n    opts.formatters = Object.assign({}, defaultOptions.formatters, opts.formatters)\n\n    if (opts.prettyPrint) {\n      throw new Error('prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)')\n    }\n\n    const { enabled, onChild } = opts\n    if (enabled === false) opts.level = 'silent'\n    if (!onChild) opts.onChild = noop\n    if (!stream) {\n      if (!hasBeenTampered(process.stdout)) {\n        // If process.stdout.fd is undefined, it means that we are running\n        // in a worker thread. Let's assume we are logging to file descriptor 1.\n        stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 })\n      } else {\n        stream = process.stdout\n      }\n    }\n    return { opts, stream }\n  }\n}\n\nfunction stringify (obj, stringifySafeFn) {\n  try {\n    return JSON.stringify(obj)\n  } catch (_) {\n    try {\n      const stringify = stringifySafeFn || this[stringifySafeSym]\n      return stringify(obj)\n    } catch (_) {\n      return '\"[unable to serialize, circular reference is too complex to analyze]\"'\n    }\n  }\n}\n\nfunction buildFormatters (level, bindings, log) {\n  return {\n    level,\n    bindings,\n    log\n  }\n}\n\n/**\n * Convert a string integer file descriptor to a proper native integer\n * file descriptor.\n *\n * @param {string} destination The file descriptor string to attempt to convert.\n *\n * @returns {Number}\n */\nfunction normalizeDestFileDescriptor (destination) {\n  const fd = Number(destination)\n  if (typeof destination === 'string' && Number.isFinite(fd)) {\n    return fd\n  }\n  // destination could be undefined if we are in a worker\n  if (destination === undefined) {\n    // This is stdout in UNIX systems\n    return 1\n  }\n  return destination\n}\n\nmodule.exports = {\n  noop,\n  buildSafeSonicBoom,\n  asChindings,\n  asJson,\n  genLog,\n  createArgsNormalizer,\n  stringify,\n  buildFormatters,\n  normalizeDestFileDescriptor\n}\n"
  },
  {
    "path": "lib/transport-stream.js",
    "content": "'use strict'\n\nconst { realImport, realRequire } = require('real-require')\n\nmodule.exports = loadTransportStreamBuilder\n\n/**\n * Loads & returns a function to build transport streams\n * @param {string} target\n * @returns {Promise<function(object): Promise<import('node:stream').Writable>>}\n * @throws {Error} In case the target module does not export a function\n */\nasync function loadTransportStreamBuilder (target) {\n  let fn\n  try {\n    const toLoad = target.startsWith('file://') ? target : 'file://' + target\n\n    if (toLoad.endsWith('.ts') || toLoad.endsWith('.cts')) {\n      // TODO: add support for the TSM modules loader ( https://github.com/lukeed/tsm ).\n      if (process[Symbol.for('ts-node.register.instance')]) {\n        realRequire('ts-node/register')\n      } else if (process.env && process.env.TS_NODE_DEV) {\n        realRequire('ts-node-dev')\n      }\n      // TODO: Support ES imports once tsc, tap & ts-node provide better compatibility guarantees.\n      fn = realRequire(decodeURIComponent(target))\n    } else {\n      fn = (await realImport(toLoad))\n    }\n  } catch (error) {\n    // See this PR for details: https://github.com/pinojs/thread-stream/pull/34\n    if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) {\n      fn = realRequire(target)\n    } else if (error.code === undefined || error.code === 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') {\n      // When bundled with pkg, an undefined error is thrown when called with realImport\n      // When bundled with pkg and using node v20, an ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING error is thrown when called with realImport\n      // More info at: https://github.com/pinojs/thread-stream/issues/143\n      try {\n        fn = realRequire(decodeURIComponent(target))\n      } catch {\n        throw error\n      }\n    } else {\n      throw error\n    }\n  }\n\n  // Depending on how the default export is performed, and on how the code is\n  // transpiled, we may find cases of two nested \"default\" objects.\n  // See https://github.com/pinojs/pino/issues/1243#issuecomment-982774762\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn === 'object') fn = fn.default\n  if (typeof fn !== 'function') throw Error('exported worker is not a function')\n\n  return fn\n}\n"
  },
  {
    "path": "lib/transport.js",
    "content": "'use strict'\n\nconst { createRequire } = require('module')\nconst { existsSync } = require('node:fs')\nconst getCallers = require('./caller')\nconst { join, isAbsolute, sep } = require('node:path')\nconst { fileURLToPath } = require('node:url')\nconst sleep = require('atomic-sleep')\nconst onExit = require('on-exit-leak-free')\nconst ThreadStream = require('thread-stream')\n\nconst { transportUsesMultistreamSym } = require('./symbols')\n\nfunction setupOnExit (stream) {\n  // This is leak free, it does not leave event handlers\n  onExit.register(stream, autoEnd)\n  onExit.registerBeforeExit(stream, flush)\n\n  stream.on('close', function () {\n    onExit.unregister(stream)\n  })\n}\n\n// Check if preload flags exist in execArgv.\n// During preload phase (require.main undefined), we pass empty execArgv to prevent infinite worker spawning.\n// We don't try to filter and pass other flags because many (like --stack-trace-limit, --tls-cipher-list)\n// aren't valid for worker threads and would cause ERR_WORKER_INVALID_EXEC_ARGV.\nfunction hasPreloadFlags () {\n  const execArgv = process.execArgv\n  for (let i = 0; i < execArgv.length; i++) {\n    const arg = execArgv[i]\n    if (arg === '--import' || arg === '--require' || arg === '-r') {\n      return true\n    }\n    if (arg.startsWith('--import=') || arg.startsWith('--require=') || arg.startsWith('-r=')) {\n      return true\n    }\n  }\n  return false\n}\n\nfunction sanitizeNodeOptions (nodeOptions) {\n  const tokens = nodeOptions.match(/(?:[^\\s\"']+|\"[^\"]*\"|'[^']*')+/g)\n  if (!tokens) {\n    return nodeOptions\n  }\n\n  const sanitized = []\n  let changed = false\n\n  for (let i = 0; i < tokens.length; i++) {\n    const token = tokens[i]\n\n    if (token === '--require' || token === '-r' || token === '--import') {\n      const next = tokens[i + 1]\n      if (next && shouldDropPreload(next)) {\n        changed = true\n        i++\n        continue\n      }\n\n      sanitized.push(token)\n      if (next) {\n        sanitized.push(next)\n        i++\n      }\n      continue\n    }\n\n    if (token.startsWith('--require=') || token.startsWith('-r=') || token.startsWith('--import=')) {\n      const value = token.slice(token.indexOf('=') + 1)\n      if (shouldDropPreload(value)) {\n        changed = true\n        continue\n      }\n    }\n\n    sanitized.push(token)\n  }\n\n  return changed ? sanitized.join(' ') : nodeOptions\n}\n\nfunction shouldDropPreload (value) {\n  const unquoted = stripQuotes(value)\n  if (!unquoted) {\n    return false\n  }\n\n  let path = unquoted\n  if (path.startsWith('file://')) {\n    try {\n      path = fileURLToPath(path)\n    } catch {\n      return false\n    }\n  }\n\n  return isAbsolute(path) && !existsSync(path)\n}\n\nfunction stripQuotes (value) {\n  const first = value[0]\n  const last = value[value.length - 1]\n\n  if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\")) {\n    return value.slice(1, -1)\n  }\n\n  return value\n}\n\nfunction buildStream (filename, workerData, workerOpts, sync, name) {\n  // When pino is loaded during a preload phase (via --import or --require),\n  // pass empty execArgv to prevent infinite spawning. Each worker would\n  // otherwise re-run the preload, creating another transport.\n  if (!workerOpts.execArgv && hasPreloadFlags() && require.main === undefined) {\n    workerOpts = {\n      ...workerOpts,\n      execArgv: []\n    }\n  }\n\n  if (!workerOpts.env && process.env.NODE_OPTIONS) {\n    const nodeOptions = sanitizeNodeOptions(process.env.NODE_OPTIONS)\n    if (nodeOptions !== process.env.NODE_OPTIONS) {\n      workerOpts = {\n        ...workerOpts,\n        env: {\n          ...process.env,\n          NODE_OPTIONS: nodeOptions\n        }\n      }\n    }\n  }\n\n  workerOpts = { ...workerOpts, name }\n\n  const stream = new ThreadStream({\n    filename,\n    workerData,\n    workerOpts,\n    sync\n  })\n\n  stream.on('ready', onReady)\n  stream.on('close', function () {\n    process.removeListener('exit', onExit)\n  })\n\n  process.on('exit', onExit)\n\n  function onReady () {\n    process.removeListener('exit', onExit)\n    stream.unref()\n\n    if (workerOpts.autoEnd !== false) {\n      setupOnExit(stream)\n    }\n  }\n\n  function onExit () {\n    /* istanbul ignore next */\n    if (stream.closed) {\n      return\n    }\n    stream.flushSync()\n    // Apparently there is a very sporadic race condition\n    // that in certain OS would prevent the messages to be flushed\n    // because the thread might not have been created still.\n    // Unfortunately we need to sleep(100) in this case.\n    sleep(100)\n    stream.end()\n  }\n\n  return stream\n}\n\nfunction autoEnd (stream) {\n  stream.ref()\n  stream.flushSync()\n  stream.end()\n  stream.once('close', function () {\n    stream.unref()\n  })\n}\n\nfunction flush (stream) {\n  stream.flushSync()\n}\n\nfunction transport (fullOptions) {\n  const { pipeline, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions\n\n  const options = {\n    ...fullOptions.options\n  }\n\n  let usesMultistream = false\n\n  // Backwards compatibility\n  const callers = typeof caller === 'string' ? [caller] : caller\n\n  // This will be eventually modified by bundlers\n  const bundlerOverrides = (typeof globalThis === 'object' &&\n    Object.prototype.hasOwnProperty.call(globalThis, '__bundlerPathsOverrides') &&\n    globalThis.__bundlerPathsOverrides &&\n    typeof globalThis.__bundlerPathsOverrides === 'object')\n    ? globalThis.__bundlerPathsOverrides\n    : Object.create(null)\n\n  let target = fullOptions.target\n\n  if (target && targets) {\n    throw new Error('only one of target or targets can be specified')\n  }\n\n  if (targets) {\n    target = bundlerOverrides['pino-worker'] || join(__dirname, 'worker.js')\n    options.targets = targets.filter(dest => dest.target).map((dest) => {\n      return {\n        ...dest,\n        target: fixTarget(dest.target)\n      }\n    })\n    options.pipelines = targets.filter(dest => dest.pipeline).map((dest) => {\n      return dest.pipeline.map((t) => {\n        return {\n          ...t,\n          level: dest.level, // duplicate the pipeline `level` property defined in the upper level\n          target: fixTarget(t.target)\n        }\n      })\n    })\n\n    usesMultistream = options.targets.length + options.pipelines.length > 1\n  } else if (pipeline) {\n    target = bundlerOverrides['pino-worker'] || join(__dirname, 'worker.js')\n    options.pipelines = [pipeline.map((dest) => {\n      return {\n        ...dest,\n        target: fixTarget(dest.target)\n      }\n    })]\n  }\n\n  if (levels) {\n    options.levels = levels\n  }\n\n  if (dedupe) {\n    options.dedupe = dedupe\n  }\n\n  options.pinoWillSendConfig = true\n\n  const name = (targets || pipeline) ? 'pino.transport' : target\n  const stream = buildStream(fixTarget(target), options, worker, sync, name)\n  if (usesMultistream) {\n    stream[transportUsesMultistreamSym] = true\n  }\n  return stream\n\n  function fixTarget (origin) {\n    origin = bundlerOverrides[origin] || origin\n\n    if (isAbsolute(origin) || origin.indexOf('file://') === 0) {\n      return origin\n    }\n\n    if (origin === 'pino/file') {\n      return join(__dirname, '..', 'file.js')\n    }\n\n    let fixTarget\n\n    for (const filePath of callers) {\n      try {\n        const context = filePath === 'node:repl'\n          ? process.cwd() + sep\n          : filePath\n\n        fixTarget = createRequire(context).resolve(origin)\n        break\n      } catch (err) {\n        // Silent catch\n        continue\n      }\n    }\n\n    if (!fixTarget) {\n      throw new Error(`unable to determine transport target for \"${origin}\"`)\n    }\n\n    return fixTarget\n  }\n}\n\nmodule.exports = transport\n"
  },
  {
    "path": "lib/worker.js",
    "content": "'use strict'\n\nconst EE = require('node:events')\nconst { pipeline, PassThrough } = require('node:stream')\nconst pino = require('../pino.js')\nconst build = require('pino-abstract-transport')\nconst loadTransportStreamBuilder = require('./transport-stream')\n\n// This file is not checked by the code coverage tool,\n// as it is not reliable.\n\n/* istanbul ignore file */\n\n/*\n * > Multiple targets & pipelines\n *\n *\n * ┌─────────────────────────────────────────────────┐    ┌─────┐\n * │                                                 │    │  p  │\n * │                                                 │    │  i  │\n * │                   target                        │    │  n  │\n * │               │ ────────────────────────────────┼────┤  o  │\n * │   targets     │   target                        │    │  .  │\n * │ ────────────► │ ────────────────────────────────┼────┤  m  │       source\n * │               │   target                        │    │  u  │         │\n * │               │ ────────────────────────────────┼────┤  l  │         │write\n * │               │                                 │    │  t  │         ▼\n * │               │  pipeline   ┌───────────────┐   │    │  i  │      ┌────────┐\n * │               │ ──────────► │  PassThrough  ├───┼────┤  s  ├──────┤        │\n * │               │             └───────────────┘   │    │  t  │ write│ Thread │\n * │               │                                 │    │  r  │◄─────┤ Stream │\n * │               │  pipeline   ┌───────────────┐   │    │  e  │      │        │\n * │               │ ──────────► │  PassThrough  ├───┼────┤  a  │      └────────┘\n * │                             └───────────────┘   │    │  m  │\n * │                                                 │    │     │\n * └─────────────────────────────────────────────────┘    └─────┘\n *\n *\n *\n *  > One single pipeline or target\n *\n *\n *                                                           source\n *                                                             │\n * ┌────────────────────────────────────────────────┐          │write\n * │                                                │          ▼\n * │                                                │      ┌────────┐\n * │   targets     │   target                       │      │        │\n * │ ────────────► │  ──────────────────────────────┤      │        │\n * │               │                                │      │        │\n * │                                                ├──────┤        │\n * │                                                │      │        │\n * │                                                │      │        │\n * │                     OR                         │      │        │\n * │                                                │      │        │\n * │                                                │      │        │\n * │                               ┌──────────────┐ │      │        │\n * │   targets     │   pipeline    │              │ │      │ Thread │\n * │ ────────────► │  ────────────►│ PassThrough  ├─┤      │ Stream │\n * │               │               │              │ │      │        │\n * │                               └──────────────┘ │      │        │\n * │                                                │      │        │\n * │                     OR                         │ write│        │\n * │                                                │◄─────┤        │\n * │                                                │      │        │\n * │                ┌──────────────┐                │      │        │\n * │    pipeline    │              │                │      │        │\n * │ ──────────────►│ PassThrough  ├────────────────┤      │        │\n * │                │              │                │      │        │\n * │                └──────────────┘                │      └────────┘\n * │                                                │\n * │                                                │\n * └────────────────────────────────────────────────┘\n */\n\nmodule.exports = async function ({ targets, pipelines, levels, dedupe }) {\n  const targetStreams = []\n\n  // Process targets\n  if (targets && targets.length) {\n    targets = await Promise.all(targets.map(async (t) => {\n      const fn = await loadTransportStreamBuilder(t.target)\n      const stream = await fn(t.options)\n      return {\n        level: t.level,\n        stream\n      }\n    }))\n\n    targetStreams.push(...targets)\n  }\n\n  // Process pipelines\n  if (pipelines && pipelines.length) {\n    pipelines = await Promise.all(\n      pipelines.map(async (p) => {\n        let level\n        const pipeDests = await Promise.all(\n          p.map(async (t) => {\n            // level assigned to pipeline is duplicated over all its targets, just store it\n            level = t.level\n            const fn = await loadTransportStreamBuilder(t.target)\n            const stream = await fn(t.options)\n            return stream\n          }\n          ))\n\n        return {\n          level,\n          stream: createPipeline(pipeDests)\n        }\n      })\n    )\n    targetStreams.push(...pipelines)\n  }\n\n  // Skip building the multistream step if either one single pipeline or target is defined and\n  // return directly the stream instance back to TreadStream.\n  // This is equivalent to define either:\n  //\n  // pino.transport({ target: ... })\n  //\n  // OR\n  //\n  // pino.transport({ pipeline: ... })\n  if (targetStreams.length === 1) {\n    return targetStreams[0].stream\n  } else {\n    return build(process, {\n      parse: 'lines',\n      metadata: true,\n      close (err, cb) {\n        let expected = 0\n        for (const transport of targetStreams) {\n          expected++\n          transport.stream.on('close', closeCb)\n          transport.stream.end()\n        }\n\n        function closeCb () {\n          if (--expected === 0) {\n            cb(err)\n          }\n        }\n      }\n    })\n  }\n\n  // TODO: Why split2 was not used for pipelines?\n  function process (stream) {\n    const multi = pino.multistream(targetStreams, { levels, dedupe })\n    // TODO manage backpressure\n    stream.on('data', function (chunk) {\n      const { lastTime, lastMsg, lastObj, lastLevel } = this\n      multi.lastLevel = lastLevel\n      multi.lastTime = lastTime\n      multi.lastMsg = lastMsg\n      multi.lastObj = lastObj\n\n      // TODO handle backpressure\n      multi.write(chunk + '\\n')\n    })\n  }\n\n  /**\n * Creates a pipeline using the provided streams and return an instance of `PassThrough` stream\n * as a source for the pipeline.\n *\n * @param {(TransformStream|WritableStream)[]} streams An array of streams.\n *   All intermediate streams in the array *MUST* be `Transform` streams and only the last one `Writable`.\n * @returns A `PassThrough` stream instance representing the source stream of the pipeline\n */\n  function createPipeline (streams) {\n    const ee = new EE()\n    const stream = new PassThrough({\n      autoDestroy: true,\n      destroy (_, cb) {\n        ee.on('error', cb)\n        ee.on('closed', cb)\n      }\n    })\n\n    pipeline(stream, ...streams, function (err) {\n      if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {\n        ee.emit('error', err)\n        return\n      }\n\n      ee.emit('closed')\n    })\n\n    return stream\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"pino\",\n  \"version\": \"10.3.1\",\n  \"description\": \"super fast, all natural json logger\",\n  \"main\": \"pino.js\",\n  \"type\": \"commonjs\",\n  \"types\": \"pino.d.ts\",\n  \"browser\": \"./browser.js\",\n  \"scripts\": {\n    \"borp\": \"borp --timeout 60000 --coverage --check-coverage --lines 95 --functions 95 --branches 95 --statements 95\",\n    \"docs\": \"docsify serve\",\n    \"browser-test\": \"airtap --local 8080 test/browser*test.js\",\n    \"lint\": \"eslint .\",\n    \"prepublishOnly\": \"node test/internals/version.test.js\",\n    \"test\": \"npm run lint && npm run transpile && npm run borp && jest test/jest && npm run test-types\",\n    \"test-ci\": \"npm run lint && npm run transpile && npm run borp && npm run test-types\",\n    \"test-ci-pnpm\": \"pnpm run lint && npm run transpile && borp --timeout 60000 && pnpm run test-types\",\n    \"test-ci-yarn-pnp\": \"yarn run lint && npm run transpile && borp --timeout 60000\",\n    \"test-types\": \"tsc && tstyche && ts-node test/types/pino.ts && attw --pack .\",\n    \"test:smoke\": \"smoker smoke:pino && smoker smoke:browser && smoker smoke:file\",\n    \"smoke:pino\": \"node ./pino.js\",\n    \"smoke:browser\": \"node ./browser.js\",\n    \"smoke:file\": \"node ./file.js\",\n    \"transpile\": \"node ./test/fixtures/ts/transpile.cjs\",\n    \"cov-ui\": \"tap --ts --coverage-report=html\",\n    \"bench\": \"node benchmarks/utils/runbench all\",\n    \"bench-basic\": \"node benchmarks/utils/runbench basic\",\n    \"bench-object\": \"node benchmarks/utils/runbench object\",\n    \"bench-deep-object\": \"node benchmarks/utils/runbench deep-object\",\n    \"bench-multi-arg\": \"node benchmarks/utils/runbench multi-arg\",\n    \"bench-long-string\": \"node benchmarks/utils/runbench long-string\",\n    \"bench-child\": \"node benchmarks/utils/runbench child\",\n    \"bench-child-child\": \"node benchmarks/utils/runbench child-child\",\n    \"bench-child-creation\": \"node benchmarks/utils/runbench child-creation\",\n    \"bench-formatters\": \"node benchmarks/utils/runbench formatters\",\n    \"update-bench-doc\": \"node benchmarks/utils/generate-benchmark-doc > docs/benchmarks.md\"\n  },\n  \"bin\": {\n    \"pino\": \"./bin.js\"\n  },\n  \"precommit\": \"test\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pinojs/pino.git\"\n  },\n  \"keywords\": [\n    \"fast\",\n    \"logger\",\n    \"stream\",\n    \"json\"\n  ],\n  \"author\": \"Matteo Collina <hello@matteocollina.com>\",\n  \"contributors\": [\n    \"David Mark Clements <huperekchuno@googlemail.com>\",\n    \"James Sumners <james.sumners@gmail.com>\",\n    \"Thomas Watson Steen <w@tson.dk> (https://twitter.com/wa7son)\"\n  ],\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/pinojs/pino/issues\"\n  },\n  \"homepage\": \"https://getpino.io\",\n  \"devDependencies\": {\n    \"@arethetypeswrong/cli\": \"^0.18.1\",\n    \"@matteo.collina/tspl\": \"^0.2.0\",\n    \"@types/flush-write-stream\": \"^1.0.0\",\n    \"@types/node\": \"^25.0.3\",\n    \"airtap\": \"5.0.0\",\n    \"bole\": \"^5.0.5\",\n    \"borp\": \"^0.21.0\",\n    \"bunyan\": \"^1.8.14\",\n    \"debug\": \"^4.3.4\",\n    \"docsify-cli\": \"^4.4.4\",\n    \"eslint\": \"^9.37.0\",\n    \"eslint-plugin-import\": \"^2.26.0\",\n    \"eslint-plugin-n\": \"17.23.2\",\n    \"eslint-plugin-node\": \"^11.1.0\",\n    \"eslint-plugin-promise\": \"^6.0.0\",\n    \"execa\": \"^5.0.0\",\n    \"fastbench\": \"^1.0.1\",\n    \"fastify-tsconfig\": \"^3.0.0\",\n    \"flush-write-stream\": \"^2.0.0\",\n    \"import-fresh\": \"^3.2.1\",\n    \"jest\": \"^30.0.3\",\n    \"log\": \"^6.0.0\",\n    \"loglevel\": \"^1.6.7\",\n    \"midnight-smoker\": \"1.1.1\",\n    \"neostandard\": \"^0.12.2\",\n    \"pino-pretty\": \"^13.0.0\",\n    \"pre-commit\": \"^1.2.2\",\n    \"proxyquire\": \"^2.1.3\",\n    \"pump\": \"^3.0.0\",\n    \"rimraf\": \"^6.0.1\",\n    \"semver\": \"^7.3.7\",\n    \"split2\": \"^4.0.0\",\n    \"steed\": \"^1.1.3\",\n    \"strip-ansi\": \"^6.0.0\",\n    \"tape\": \"^5.5.3\",\n    \"through2\": \"^4.0.0\",\n    \"ts-node\": \"^10.9.1\",\n    \"tstyche\": \"^6.0.2\",\n    \"typescript\": \"~5.9.2\",\n    \"winston\": \"^3.7.2\"\n  },\n  \"dependencies\": {\n    \"@pinojs/redact\": \"^0.4.0\",\n    \"atomic-sleep\": \"^1.0.0\",\n    \"on-exit-leak-free\": \"^2.1.0\",\n    \"pino-abstract-transport\": \"^3.0.0\",\n    \"pino-std-serializers\": \"^7.0.0\",\n    \"process-warning\": \"^5.0.0\",\n    \"quick-format-unescaped\": \"^4.0.3\",\n    \"real-require\": \"^0.2.0\",\n    \"safe-stable-stringify\": \"^2.3.1\",\n    \"sonic-boom\": \"^4.0.1\",\n    \"thread-stream\": \"^4.0.0\"\n  }\n}\n"
  },
  {
    "path": "pino.d.ts",
    "content": "// Project: https://github.com/pinojs/pino.git, http://getpino.io\n// Definitions by: Peter Snider <https://github.com/psnider>\n//                 BendingBender <https://github.com/BendingBender>\n//                 Christian Rackerseder <https://github.com/screendriver>\n//                 GP <https://github.com/paambaati>\n//                 Alex Ferrando <https://github.com/alferpal>\n//                 Oleksandr Sidko <https://github.com/mortiy>\n//                 Harris Lummis <https://github.com/lummish>\n//                 Raoul Jaeckel <https://github.com/raoulus>\n//                 Cory Donkin <https://github.com/Cooryd>\n//                 Adam Vigneaux <https://github.com/AdamVig>\n//                 Austin Beer <https://github.com/austin-beer>\n//                 Michel Nemnom <https://github.com/Pegase745>\n//                 Igor Savin <https://github.com/kibertoad>\n//                 James Bromwell <https://github.com/thw0rted>\n\nimport type { EventEmitter } from 'events'\nimport * as pinoStdSerializers from 'pino-std-serializers'\nimport type { SonicBoom, SonicBoomOpts } from 'sonic-boom'\nimport ThreadStream from 'thread-stream'\nimport type { WorkerOptions } from 'worker_threads'\n\ndeclare namespace pino {\n  /// Non-exported types and interfaces\n\n    type TimeFn = () => string\n    type MixinFn<CustomLevels extends string = never> = (mergeObject: object, level: number, logger:Logger<CustomLevels>) => object\n    type MixinMergeStrategyFn = (mergeObject: object, mixinObject: object) => object\n\n    type CustomLevelLogger<CustomLevels extends string, UseOnlyCustomLevels extends boolean = boolean> = {\n      /**\n       * Define additional logging levels.\n       */\n      customLevels: { [level in CustomLevels]: number };\n      /**\n       * Use only defined `customLevels` and omit Pino's levels.\n       */\n      useOnlyCustomLevels: UseOnlyCustomLevels;\n    } & {\n      // This will override default log methods\n      [K in Exclude<Level, CustomLevels>]: UseOnlyCustomLevels extends true ? never : LogFn;\n    } & {\n      [level in CustomLevels]: LogFn;\n    }\n\n    /**\n     * A synchronous callback that will run on each creation of a new child.\n     * @param child: The newly created child logger instance.\n     */\n    type OnChildCallback<CustomLevels extends string = never> = (child: Logger<CustomLevels>) => void\n\n    export interface redactOptions {\n      paths: string[];\n      censor?: string | ((value: unknown, path: string[]) => unknown);\n      remove?: boolean;\n    }\n\n    export interface LoggerExtras<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> extends EventEmitter {\n      /**\n       * Exposes the Pino package version. Also available on the exported pino function.\n       */\n      readonly version: string;\n\n      levels: LevelMapping;\n\n      /**\n       * Outputs the level as a string instead of integer.\n       */\n      useLevelLabels: boolean;\n      /**\n       * Returns the integer value for the logger instance's logging level.\n       */\n      levelVal: number;\n\n      /**\n       * Creates a child logger, setting all key-value pairs in `bindings` as properties in the log lines. All serializers will be applied to the given pair.\n       * Child loggers use the same output stream as the parent and inherit the current log level of the parent at the time they are spawned.\n       * From v2.x.x the log level of a child is mutable (whereas in v1.x.x it was immutable), and can be set independently of the parent.\n       * If a `level` property is present in the object passed to `child` it will override the child logger level.\n       *\n       * @param bindings: an object of key-value pairs to include in log lines as properties.\n       * @param options: an options object that will override child logger inherited options.\n       * @returns a child logger instance.\n       */\n      child<ChildCustomLevels extends string = never>(bindings: Bindings, options?: ChildLoggerOptions<ChildCustomLevels>): Logger<CustomLevels | ChildCustomLevels>;\n\n      /**\n       * This can be used to modify the callback function on creation of a new child.\n       */\n      onChild: OnChildCallback<CustomLevels>;\n\n      /**\n       * Registers a listener function that is triggered when the level is changed.\n       * Note: When browserified, this functionality will only be available if the `events` module has been required elsewhere\n       * (e.g. if you're using streams in the browser). This allows for a trade-off between bundle size and functionality.\n       *\n       * @param event: only ever fires the `'level-change'` event\n       * @param listener: The listener is passed four arguments: `levelLabel`, `levelValue`, `previousLevelLabel`, `previousLevelValue`.\n       */\n      on(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n      addListener(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n      once(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n      prependListener(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n      prependOnceListener(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n      removeListener(event: 'level-change', listener: LevelChangeEventListener<CustomLevels, UseOnlyCustomLevels>): this;\n\n      /**\n       * A utility method for determining if a given log level will write to the destination.\n       */\n      isLevelEnabled(level: LevelWithSilentOrString): boolean;\n\n      /**\n       * Returns an object containing all the current bindings, cloned from the ones passed in via logger.child().\n       */\n      bindings(): Bindings;\n\n      /**\n       * Adds to the bindings of this logger instance.\n       * Note: Does not overwrite bindings. Can potentially result in duplicate keys in log lines.\n       *\n       * @param bindings: an object of key-value pairs to include in log lines as properties.\n       */\n      setBindings(bindings: Bindings): void;\n\n      /**\n       * Flushes the content of the buffer when using pino.destination({ sync: false }).\n       * call the callback when finished\n       */\n      flush(cb?: (err?: Error) => void): void;\n    }\n\n    /// Exported types and interfaces\n    export interface BaseLogger {\n      /**\n       * Set this property to the desired logging level. In order of priority, available levels are:\n       *\n       * - 'fatal'\n       * - 'error'\n       * - 'warn'\n       * - 'info'\n       * - 'debug'\n       * - 'trace'\n       *\n       * The logging level is a __minimum__ level. For instance if `logger.level` is `'info'` then all `'fatal'`, `'error'`, `'warn'`,\n       * and `'info'` logs will be enabled.\n       *\n       * You can pass `'silent'` to disable logging.\n       */\n      level: LevelWithSilentOrString;\n\n      /**\n       * Log at `'fatal'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      fatal: LogFn;\n      /**\n       * Log at `'error'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      error: LogFn;\n      /**\n       * Log at `'warn'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      warn: LogFn;\n      /**\n       * Log at `'info'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      info: LogFn;\n      /**\n       * Log at `'debug'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      debug: LogFn;\n      /**\n       * Log at `'trace'` level the given msg. If the first argument is an object, all its properties will be included in the JSON line.\n       * If more args follows `msg`, these will be used to format `msg` using `util.format`.\n       *\n       * @typeParam T: the interface of the object being serialized. Default is object.\n       * @param obj: object to be serialized\n       * @param msg: the log message to write\n       * @param ...args: format string values when `msg` is a format string\n       */\n      trace: LogFn;\n      /**\n       * Noop function.\n       */\n      silent: LogFn;\n\n      /**\n       * Get `msgPrefix` of the logger instance.\n       *\n       * See {@link https://github.com/pinojs/pino/blob/main/docs/api.md#msgprefix-string}.\n       */\n      get msgPrefix(): string | undefined;\n    }\n\n    export type Bindings = Record<string, any>\n\n    export type Level = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'\n    export type LevelOrString = Level | (string & {})\n    export type LevelWithSilent = Level | 'silent'\n    export type LevelWithSilentOrString = LevelWithSilent | (string & {})\n\n    export type SerializerFn = (value: any) => any\n    export type WriteFn = (o: object) => void\n\n    export type LevelChangeEventListener<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> = (\n      lvl: LevelWithSilentOrString,\n      val: number,\n      prevLvl: LevelWithSilentOrString,\n      prevVal: number,\n      logger: Logger<CustomLevels, UseOnlyCustomLevels>\n    ) => void\n\n    export type LogDescriptor = Record<string, any>\n\n    export type Logger<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> = BaseLogger & LoggerExtras<CustomLevels> & CustomLevelLogger<CustomLevels, UseOnlyCustomLevels>\n\n    export type SerializedError = pinoStdSerializers.SerializedError\n    export type SerializedResponse = pinoStdSerializers.SerializedResponse\n    export type SerializedRequest = pinoStdSerializers.SerializedRequest\n\n    export interface TransportTargetOptions<TransportOptions = Record<string, any>> {\n      target: string\n      options?: TransportOptions\n      level?: LevelWithSilentOrString\n    }\n\n    export interface TransportBaseOptions<TransportOptions = Record<string, any>> {\n      options?: TransportOptions\n      worker?: WorkerOptions & { autoEnd?: boolean }\n    }\n\n    export interface TransportSingleOptions<TransportOptions = Record<string, any>> extends TransportBaseOptions<TransportOptions> {\n      target: string\n    }\n\n    export interface TransportPipelineOptions<TransportOptions = Record<string, any>> extends TransportBaseOptions<TransportOptions> {\n      pipeline: TransportSingleOptions<TransportOptions>[]\n      level?: LevelWithSilentOrString\n    }\n\n    export interface TransportMultiOptions<TransportOptions = Record<string, any>> extends TransportBaseOptions<TransportOptions> {\n      targets: readonly (TransportTargetOptions<TransportOptions> | TransportPipelineOptions<TransportOptions>)[],\n      levels?: Record<string, number>\n      dedupe?: boolean\n    }\n\n    export interface MultiStreamOptions {\n      levels?: Record<string, number>\n      dedupe?: boolean\n    }\n\n    export interface DestinationStream {\n      write(msg: string): void;\n    }\n\n    interface DestinationStreamHasMetadata {\n      [symbols.needsMetadataGsym]: true;\n      lastLevel: number;\n      lastTime: string;\n      lastMsg: string;\n      lastObj: object;\n      lastLogger: Logger;\n    }\n\n    export type DestinationStreamWithMetadata = DestinationStream & ({ [symbols.needsMetadataGsym]?: false } | DestinationStreamHasMetadata)\n\n    export interface StreamEntry<TLevel = Level> {\n      stream: DestinationStream\n      level?: TLevel\n    }\n\n    export interface MultiStreamRes<TOriginLevel = Level> {\n      write: (data: any) => void,\n      add: <TLevel = Level>(dest: StreamEntry<TLevel> | DestinationStream) => MultiStreamRes<TOriginLevel & TLevel>,\n      flushSync: () => void,\n      minLevel: number,\n      streams: StreamEntry<TOriginLevel>[],\n      clone<const TLevel = Level>(level: TLevel): MultiStreamRes<TLevel>,\n    }\n\n    export interface LevelMapping {\n      /**\n       * Returns the mappings of level names to their respective internal number representation.\n       */\n      values: { [level: string]: number };\n      /**\n       * Returns the mappings of level internal level numbers to their string representations.\n       */\n      labels: { [level: number]: string };\n    }\n\n    type PlaceholderSpecifier = 'd' | 's' | 'j' | 'o' | 'O'\n    type PlaceholderTypeMapping<T extends PlaceholderSpecifier> = T extends 'd'\n      ? number\n      : T extends 's'\n        ? unknown\n        : T extends 'j' | 'o' | 'O'\n          ? {} | null\n          : never\n\n    type ParseLogFnArgs<\n        T,\n        Acc extends unknown[] = []\n    > = T extends `${infer _}%${infer Placeholder}${infer Rest}`\n      ? Placeholder extends PlaceholderSpecifier\n        ? ParseLogFnArgs<Rest, [...Acc, PlaceholderTypeMapping<Placeholder>]>\n        : ParseLogFnArgs<Rest, Acc>\n      : Acc\n\n    export interface LogFnFields {}\n\n    export interface LogFn {\n        // Simple case: When first argument is always a string message, use parsed arguments directly\n        <TMsg extends string = string>(msg: TMsg, ...args: ParseLogFnArgs<TMsg>): void;\n        // Complex case: When first argument can be any type - if it's a string, no message needed; otherwise require a message\n        <T, TMsg extends string = string>(obj: [T] extends [object] ? T & LogFnFields : T, msg?: T extends string ? never : TMsg, ...args: ParseLogFnArgs<TMsg> | []): void;\n        // Complex case with type safety: Same as above but ensures ParseLogFnArgs is a valid tuple before using it\n        <T, TMsg extends string = string>(obj: [T] extends [object] ? T & LogFnFields : T, msg?: T extends string ? never : TMsg, ...args: ParseLogFnArgs<TMsg> extends [unknown, ...unknown[]] ? ParseLogFnArgs<TMsg> : unknown[]): void;\n    }\n\n    export interface LoggerOptions<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> {\n      transport?: TransportSingleOptions | TransportMultiOptions | TransportPipelineOptions\n      /**\n       * Avoid error causes by circular references in the object tree. Default: `true`.\n       */\n      safe?: boolean;\n      /**\n       * The name of the logger. Default: `undefined`.\n       */\n      name?: string;\n      /**\n       * an object containing functions for custom serialization of objects.\n       * These functions should return an JSONifiable object and they should never throw. When logging an object,\n       * each top-level property matching the exact key of a serializer will be serialized using the defined serializer.\n       */\n      serializers?: { [key: string]: SerializerFn };\n      /**\n       * Enables or disables the inclusion of a timestamp in the log message. If a function is supplied, it must\n       * synchronously return a JSON string representation of the time. If set to `false`, no timestamp will be included in the output.\n       * See stdTimeFunctions for a set of available functions for passing in as a value for this option.\n       * Caution: any sort of formatted time will significantly slow down Pino's performance.\n       */\n      timestamp?: TimeFn | boolean;\n      /**\n       * One of the supported levels or `silent` to disable logging. Any other value defines a custom level and\n       * requires supplying a level value via `levelVal`. Default: 'info'.\n       */\n      level?: LevelWithSilentOrString;\n\n      /**\n       * Use this option to define additional logging levels.\n       * The keys of the object correspond the namespace of the log level, and the values should be the numerical value of the level.\n       */\n      customLevels?: { [level in CustomLevels]: number };\n\n      /**\n       * Use this option to only use defined `customLevels` and omit Pino's levels.\n       * Logger's default `level` must be changed to a value in `customLevels` in order to use `useOnlyCustomLevels`\n       * Warning: this option may not be supported by downstream transports.\n       */\n      useOnlyCustomLevels?: UseOnlyCustomLevels;\n\n      /**\n       *  Use this option to define custom comparison of log levels.\n       *  Useful to compare custom log levels or non-standard level values.\n       *  Default: \"ASC\"\n       */\n      levelComparison?: 'ASC' | 'DESC' | ((current: number, expected: number) => boolean);\n\n      /**\n       * If provided, the `mixin` function is called each time one of the active logging methods\n       * is called. The function must synchronously return an object. The properties of the\n       * returned object will be added to the logged JSON.\n       */\n      mixin?: MixinFn<CustomLevels>;\n\n      /**\n       * If provided, the `mixinMergeStrategy` function is called each time one of the active\n       * logging methods is called. The first parameter is the value `mergeObject` or an empty object,\n       * the second parameter is the value resulting from `mixin()` or an empty object.\n       * The function must synchronously return an object.\n       */\n      mixinMergeStrategy?: MixinMergeStrategyFn\n\n      /**\n       * As an array, the redact option specifies paths that should have their values redacted from any log output.\n       *\n       * Each path must be a string using a syntax which corresponds to JavaScript dot and bracket notation.\n       *\n       * If an object is supplied, three options can be specified:\n       *\n       *      paths (String[]): Required. An array of paths\n       *      censor (String): Optional. A value to overwrite key which are to be redacted. Default: '[Redacted]'\n       *      remove (Boolean): Optional. Instead of censoring the value, remove both the key and the value. Default: false\n       */\n      redact?: string[] | redactOptions;\n\n      /**\n       * When defining a custom log level via level, set to an integer value to define the new level. Default: `undefined`.\n       */\n      levelVal?: number;\n      /**\n       * The string key for the 'message' in the JSON object. Default: \"msg\".\n       */\n      messageKey?: string;\n      /**\n       * The string key for the 'error' in the JSON object. Default: \"err\".\n       */\n      errorKey?: string;\n      /**\n       * The string key to place any logged object under.\n       */\n      nestedKey?: string;\n      /**\n       * Enables logging. Default: `true`.\n       */\n      enabled?: boolean;\n      /**\n       * Browser only, see http://getpino.io/#/docs/browser.\n       */\n      browser?: {\n        /**\n         * The `asObject` option will create a pino-like log object instead of passing all arguments to a console\n         * method. When `write` is set, `asObject` will always be true.\n         *\n         * @example\n         * pino.info('hi') // creates and logs {msg: 'hi', level: 30, time: <ts>}\n         */\n        asObject?: boolean;\n        /**\n         * The `asObjectBindingsOnly` option is similar to `asObject` but will keep the message and arguments\n         * unformatted. This allows to defer formatting the message to the actual call to `console` methods,\n         * where browsers then have richer formatting in their devtools than when pino will format the message to\n         * a string first.\n         *\n         * @example\n         * pino.info('hello %s', 'world') // creates and logs {level: 30, time: <ts>}, 'hello %s', 'world'\n         */\n        asObjectBindingsOnly?: boolean;\n        formatters?: {\n          /**\n           * Changes the shape of the log level.\n           * The default shape is { level: number }.\n           */\n          level?: (label: string, number: number) => object;\n          /**\n           * Changes the shape of the log object.\n           */\n          log?: (object: Record<string, unknown>) => Record<string, unknown>;\n        }\n        /**\n         * When true, attempts to capture and include the caller location (file:line:column).\n         * In object mode, adds a `caller` string property to the logged object.\n         * Otherwise, appends the caller string as an extra console argument.\n         * This is a browser-only, best-effort feature.\n         */\n        reportCaller?: boolean;\n        /**\n         * Instead of passing log messages to `console.log` they can be passed to a supplied function. If `write` is\n         * set to a single function, all logging objects are passed to this function. If `write` is an object, it\n         * can have methods that correspond to the levels. When a message is logged at a given level, the\n         * corresponding method is called. If a method isn't present, the logging falls back to using the `console`.\n         *\n         * @example\n         * const pino = require('pino')({\n         *   browser: {\n         *     write: (o) => {\n         *       // do something with o\n         *     }\n         *   }\n         * })\n         *\n         * @example\n         * const pino = require('pino')({\n         *   browser: {\n         *     write: {\n         *       info: function (o) {\n         *         //process info log object\n         *       },\n         *       error: function (o) {\n         *         //process error log object\n         *       }\n         *     }\n         *   }\n         * })\n         */\n        write?:\n          | WriteFn\n          | ({\n            fatal?: WriteFn;\n            error?: WriteFn;\n            warn?: WriteFn;\n            info?: WriteFn;\n            debug?: WriteFn;\n            trace?: WriteFn;\n          } & { [logLevel: string]: WriteFn });\n\n        /**\n         * The serializers provided to `pino` are ignored by default in the browser, including the standard\n         * serializers provided with Pino. Since the default destination for log messages is the console, values\n         * such as `Error` objects are enhanced for inspection, which they otherwise wouldn't be if the Error\n         * serializer was enabled. We can turn all serializers on or we can selectively enable them via an array.\n         *\n         * When `serialize` is `true` the standard error serializer is also enabled (see\n         * {@link https://github.com/pinojs/pino/blob/master/docs/api.md#pino-stdserializers}). This is a global\n         * serializer which will apply to any `Error` objects passed to the logger methods.\n         *\n         * If `serialize` is an array the standard error serializer is also automatically enabled, it can be\n         * explicitly disabled by including a string in the serialize array: `!stdSerializers.err` (see example).\n         *\n         * The `serialize` array also applies to any child logger serializers (see\n         * {@link https://github.com/pinojs/pino/blob/master/docs/api.md#bindingsserializers-object} for how to\n         * set child-bound serializers).\n         *\n         * Unlike server pino the serializers apply to every object passed to the logger method, if the `asObject`\n         * option is `true`, this results in the serializers applying to the first object (as in server pino).\n         *\n         * For more info on serializers see\n         * {@link https://github.com/pinojs/pino/blob/master/docs/api.md#serializers-object}.\n         *\n         * @example\n         * const pino = require('pino')({\n         *   browser: {\n         *     serialize: true\n         *   }\n         * })\n         *\n         * @example\n         * const pino = require('pino')({\n         *   serializers: {\n         *     custom: myCustomSerializer,\n         *     another: anotherSerializer\n         *   },\n         *   browser: {\n         *     serialize: ['custom']\n         *   }\n         * })\n         * // following will apply myCustomSerializer to the custom property,\n         * // but will not apply anotherSerializer to another key\n         * pino.info({custom: 'a', another: 'b'})\n         *\n         * @example\n         * const pino = require('pino')({\n         *   serializers: {\n         *     custom: myCustomSerializer,\n         *     another: anotherSerializer\n         *   },\n         *   browser: {\n         *     serialize: ['!stdSerializers.err', 'custom'] //will not serialize Errors, will serialize `custom` keys\n         *   }\n         * })\n         */\n        serialize?: boolean | string[];\n\n        /**\n         * Options for transmission of logs.\n         *\n         * @example\n         * const pino = require('pino')({\n         *   browser: {\n         *     transmit: {\n         *       level: 'warn',\n         *       send: function (level, logEvent) {\n         *         if (level === 'warn') {\n         *           // maybe send the logEvent to a separate endpoint\n         *           // or maybe analyse the messages further before sending\n         *         }\n         *         // we could also use the `logEvent.level.value` property to determine\n         *         // numerical value\n         *         if (logEvent.level.value >= 50) { // covers error and fatal\n         *\n         *           // send the logEvent somewhere\n         *         }\n         *       }\n         *     }\n         *   }\n         * })\n         */\n        transmit?: {\n          /**\n           * Specifies the minimum level (inclusive) of when the `send` function should be called, if not supplied\n           * the `send` function will be called based on the main logging `level` (set via `options.level`,\n           * defaulting to `info`).\n           */\n          level?: LevelOrString;\n          /**\n           * Remotely record log messages.\n           *\n           * @description Called after writing the log message.\n           */\n          send: (level: Level, logEvent: LogEvent) => void;\n        };\n        /**\n         * The disabled option will disable logging in browser if set to true, by default it is set to false.\n         *\n         * @example\n         * const pino = require('pino')({browser: {disabled: true}})\n         */\n        disabled?: boolean;\n      };\n      /**\n       * key-value object added as child logger to each log line. If set to null the base child logger is not added\n       */\n      base?: { [key: string]: any } | null;\n\n      /**\n       * An object containing functions for formatting the shape of the log lines.\n       * These functions should return a JSONifiable object and should never throw.\n       * These functions allow for full customization of the resulting log lines.\n       * For example, they can be used to change the level key name or to enrich the default metadata.\n       */\n      formatters?: {\n        /**\n         * Changes the shape of the log level.\n         * The default shape is { level: number }.\n         * The function takes two arguments, the label of the level (e.g. 'info') and the numeric value (e.g. 30).\n         */\n        level?: (label: string, number: number) => object;\n        /**\n         * Changes the shape of the bindings.\n         * The default shape is { pid, hostname }.\n         * The function takes a single argument, the bindings object.\n         * It will be called every time a child logger is created.\n         */\n        bindings?: (bindings: Bindings) => object;\n        /**\n         * Changes the shape of the log object.\n         * This function will be called every time one of the log methods (such as .info) is called.\n         * All arguments passed to the log method, except the message, will be pass to this function.\n         * By default it does not change the shape of the log object.\n         */\n        log?: (object: Record<string, unknown>) => Record<string, unknown>;\n      };\n\n      /**\n       * A string that would be prefixed to every message (and child message)\n       */\n      msgPrefix?: string\n\n      /**\n       * An object mapping to hook functions. Hook functions allow for customizing internal logger operations.\n       * Hook functions must be synchronous functions.\n       */\n      hooks?: {\n        /**\n         * Allows for manipulating the parameters passed to logger methods. The signature for this hook is\n         * logMethod (args, method, level) {}, where args is an array of the arguments that were passed to the\n         * log method and method is the log method itself, and level is the log level. This hook must invoke the method function by\n         * using apply, like so: method.apply(this, newArgumentsArray).\n         */\n        logMethod?: (this: Logger, args: Parameters<LogFn>, method: LogFn, level: number) => void;\n\n        /**\n         * Allows for manipulating the stringified JSON log output just before writing to various transports.\n         * This function must return a string and must be valid JSON.\n         */\n        streamWrite?: (s: string) => string;\n      };\n\n      /**\n       * Stringification limit at a specific nesting depth when logging circular object. Default: `5`.\n       */\n      depthLimit?: number\n\n      /**\n       * Stringification limit of properties/elements when logging a specific object/array with circular references. Default: `100`.\n       */\n      edgeLimit?: number\n\n      /**\n       * Optional child creation callback.\n       */\n      onChild?: OnChildCallback<CustomLevels>;\n\n      /**\n       * logs newline delimited JSON with `\\r\\n` instead of `\\n`. Default: `false`.\n       */\n      crlf?: boolean;\n    }\n\n    export interface ChildLoggerOptions<CustomLevels extends string = never> {\n      level?: LevelOrString;\n      serializers?: { [key: string]: SerializerFn };\n      customLevels?: { [level in CustomLevels]: number };\n      formatters?: {\n        level?: (label: string, number: number) => object;\n        bindings?: (bindings: Bindings) => object;\n        log?: (object: object) => object;\n      };\n      redact?: string[] | redactOptions;\n      msgPrefix?: string\n    }\n\n    /**\n     * A data structure representing a log message, it represents the arguments passed to a logger statement, the level\n     * at which they were logged and the hierarchy of child bindings.\n     *\n     * @description By default serializers are not applied to log output in the browser, but they will always be applied\n     * to `messages` and `bindings` in the `logEvent` object. This allows  us to ensure a consistent format for all\n     * values between server and client.\n     */\n    export interface LogEvent {\n      /**\n       * Unix epoch timestamp in milliseconds, the time is taken from the moment the logger method is called.\n       */\n      ts: number;\n      /**\n       * All arguments passed to logger method, (for instance `logger.info('a', 'b', 'c')` would result in `messages`\n       * array `['a', 'b', 'c']`).\n       */\n      messages: any[];\n      /**\n       * Represents each child logger (if any), and the relevant bindings.\n       *\n       * @description For instance, given `logger.child({a: 1}).child({b: 2}).info({c: 3})`, the bindings array would\n       * hold `[{a: 1}, {b: 2}]` and the `messages` array would be `[{c: 3}]`. The `bindings` are ordered according to\n       * their position in the child logger hierarchy, with the lowest index being the top of the hierarchy.\n       */\n      bindings: Bindings[];\n      /**\n       * Holds the `label` (for instance `info`), and the corresponding numerical `value` (for instance `30`).\n       * This could be important in cases where client side level values and labels differ from server side.\n       */\n      level: {\n        label: string;\n        value: number;\n      };\n    }\n\n    /// Top level variable (const) exports\n\n    /**\n     * Provides functions for serializing objects common to many projects.\n     */\n    export const stdSerializers: typeof pinoStdSerializers\n\n    /**\n     * Holds the current log format version (as output in the v property of each log record).\n     */\n    export const levels: LevelMapping\n\n    export const symbols: {\n      readonly setLevelSym: unique symbol;\n      readonly getLevelSym: unique symbol;\n      readonly levelValSym: unique symbol;\n      readonly useLevelLabelsSym: unique symbol;\n      readonly mixinSym: unique symbol;\n      readonly lsCacheSym: unique symbol;\n      readonly chindingsSym: unique symbol;\n      readonly asJsonSym: unique symbol;\n      readonly writeSym: unique symbol;\n      readonly serializersSym: unique symbol;\n      readonly redactFmtSym: unique symbol;\n      readonly timeSym: unique symbol;\n      readonly timeSliceIndexSym: unique symbol;\n      readonly streamSym: unique symbol;\n      readonly stringifySym: unique symbol;\n      readonly stringifySafeSym: unique symbol;\n      readonly stringifiersSym: unique symbol;\n      readonly endSym: unique symbol;\n      readonly formatOptsSym: unique symbol;\n      readonly messageKeySym: unique symbol;\n      readonly errorKeySym: unique symbol;\n      readonly nestedKeySym: unique symbol;\n      readonly wildcardFirstSym: unique symbol;\n      readonly needsMetadataGsym: unique symbol;\n      readonly useOnlyCustomLevelsSym: unique symbol;\n      readonly formattersSym: unique symbol;\n      readonly hooksSym: unique symbol;\n    }\n\n    /**\n     * Exposes the Pino package version. Also available on the logger instance.\n     */\n    export const version: string\n\n    /**\n     * Provides functions for generating the timestamp property in the log output. You can set the `timestamp` option during\n     * initialization to one of these functions to adjust the output format. Alternatively, you can specify your own time function.\n     * A time function must synchronously return a string that would be a valid component of a JSON string. For example,\n     * the default function returns a string like `,\"time\":1493426328206`.\n     */\n    export const stdTimeFunctions: {\n      /**\n       * The default time function for Pino. Returns a string like `,\"time\":1493426328206`.\n       */\n      epochTime: TimeFn;\n      /*\n       * Returns the seconds since Unix epoch\n       */\n      unixTime: TimeFn;\n      /**\n       * Returns an empty string. This function is used when the `timestamp` option is set to `false`.\n       */\n      nullTime: TimeFn;\n      /*\n       * Returns ISO 8601-formatted time in UTC\n       */\n      isoTime: TimeFn;\n      /*\n       * Returns RFC 3339-formatted time in UTC\n       */\n      isoTimeNano: TimeFn;\n    }\n\n    /// Exported functions\n\n    /**\n     * Create a Pino Destination instance: a stream-like object with significantly more throughput (over 30%) than a standard Node.js stream.\n     * @param [dest]: The `destination` parameter, can be a file descriptor, a file path, or an object with `dest` property pointing to a fd or path.\n     *                An ordinary Node.js `stream` file descriptor can be passed as the destination (such as the result of `fs.createWriteStream`)\n     *                but for peak log writing performance, it is strongly recommended to use `pino.destination` to create the destination stream.\n     * @returns A Sonic-Boom  stream to be used as destination for the pino function\n     */\n    export function destination (\n      dest?: number | object | string | DestinationStream | NodeJS.WritableStream | SonicBoomOpts,\n    ): SonicBoom\n\n    export function transport<TransportOptions = Record<string, any>> (\n      options: TransportSingleOptions<TransportOptions> | TransportMultiOptions<TransportOptions> | TransportPipelineOptions<TransportOptions>\n    ): ThreadStream\n\n    export function multistream<TLevel = Level> (\n      streamsArray: (DestinationStream | StreamEntry<TLevel>)[] | DestinationStream | StreamEntry<TLevel>,\n      opts?: MultiStreamOptions\n    ): MultiStreamRes<TLevel>\n\n    /// Nested version of default export for TypeScript/Babel compatibility\n\n    /**\n     * @param [optionsOrStream]: an options object or a writable stream where the logs will be written. It can also receive some log-line metadata, if the\n     * relative protocol is enabled. Default: process.stdout\n     * @returns a new logger instance.\n     */\n    function pino<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> (optionsOrStream?: LoggerOptions<CustomLevels, UseOnlyCustomLevels> | DestinationStream): Logger<CustomLevels, UseOnlyCustomLevels>\n\n    /**\n     * @param [options]: an options object\n     * @param [stream]: a writable stream where the logs will be written. It can also receive some log-line metadata, if the\n     * relative protocol is enabled. Default: process.stdout\n     * @returns a new logger instance.\n     */\n    function pino<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> (options: LoggerOptions<CustomLevels, UseOnlyCustomLevels>, stream?: DestinationStream | undefined): Logger<CustomLevels, UseOnlyCustomLevels>\n\n    /**\n     * Attach selected static members to the nested callable export, so that\n     * `const { pino } = require('pino')` exposes them (e.g. `pino.stdTimeFunctions`).\n     */\n    namespace pino {\n      const stdTimeFunctions: {\n        epochTime: TimeFn;\n        unixTime: TimeFn;\n        nullTime: TimeFn;\n        isoTime: TimeFn;\n        isoTimeNano: TimeFn;\n      }\n    }\n}\n\n/// Callable default export\n\n/**\n * @param [optionsOrStream]: an options object or a writable stream where the logs will be written. It can also receive some log-line metadata, if the\n * relative protocol is enabled. Default: process.stdout\n * @returns a new logger instance.\n */\ndeclare function pino<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> (optionsOrStream?: pino.LoggerOptions<CustomLevels, UseOnlyCustomLevels> | pino.DestinationStream): pino.Logger<CustomLevels, UseOnlyCustomLevels>\n\n/**\n * @param [options]: an options object\n * @param [stream]: a writable stream where the logs will be written. It can also receive some log-line metadata, if the\n * relative protocol is enabled. Default: process.stdout\n * @returns a new logger instance.\n */\ndeclare function pino<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean> (options: pino.LoggerOptions<CustomLevels, UseOnlyCustomLevels>, stream?: pino.DestinationStream | undefined): pino.Logger<CustomLevels, UseOnlyCustomLevels>\n\nexport = pino\n"
  },
  {
    "path": "pino.js",
    "content": "'use strict'\n\nconst os = require('node:os')\nconst stdSerializers = require('pino-std-serializers')\nconst caller = require('./lib/caller')\nconst redaction = require('./lib/redaction')\nconst time = require('./lib/time')\nconst proto = require('./lib/proto')\nconst symbols = require('./lib/symbols')\nconst { configure } = require('safe-stable-stringify')\nconst { assertDefaultLevelFound, mappings, genLsCache, genLevelComparison, assertLevelComparison } = require('./lib/levels')\nconst { DEFAULT_LEVELS, SORTING_ORDER } = require('./lib/constants')\nconst {\n  createArgsNormalizer,\n  asChindings,\n  buildSafeSonicBoom,\n  buildFormatters,\n  stringify,\n  normalizeDestFileDescriptor,\n  noop\n} = require('./lib/tools')\nconst { version } = require('./lib/meta')\nconst {\n  chindingsSym,\n  redactFmtSym,\n  serializersSym,\n  timeSym,\n  timeSliceIndexSym,\n  streamSym,\n  stringifySym,\n  stringifySafeSym,\n  stringifiersSym,\n  setLevelSym,\n  endSym,\n  formatOptsSym,\n  messageKeySym,\n  errorKeySym,\n  nestedKeySym,\n  mixinSym,\n  levelCompSym,\n  useOnlyCustomLevelsSym,\n  formattersSym,\n  hooksSym,\n  nestedKeyStrSym,\n  mixinMergeStrategySym,\n  msgPrefixSym,\n  transportUsesMultistreamSym\n} = symbols\nconst { epochTime, nullTime } = time\nconst { pid } = process\nconst hostname = os.hostname()\nconst defaultErrorSerializer = stdSerializers.err\nconst defaultOptions = {\n  level: 'info',\n  levelComparison: SORTING_ORDER.ASC,\n  levels: DEFAULT_LEVELS,\n  messageKey: 'msg',\n  errorKey: 'err',\n  nestedKey: null,\n  enabled: true,\n  base: { pid, hostname },\n  serializers: Object.assign(Object.create(null), {\n    err: defaultErrorSerializer\n  }),\n  formatters: Object.assign(Object.create(null), {\n    bindings (bindings) {\n      return bindings\n    },\n    level (label, number) {\n      return { level: number }\n    }\n  }),\n  hooks: {\n    logMethod: undefined,\n    streamWrite: undefined\n  },\n  timestamp: epochTime,\n  name: undefined,\n  redact: null,\n  customLevels: null,\n  useOnlyCustomLevels: false,\n  depthLimit: 5,\n  edgeLimit: 100\n}\n\nconst normalize = createArgsNormalizer(defaultOptions)\n\nconst serializers = Object.assign(Object.create(null), stdSerializers)\n\nfunction pino (...args) {\n  const instance = {}\n  const { opts, stream } = normalize(instance, caller(), ...args)\n\n  if (opts.level && typeof opts.level === 'string' && DEFAULT_LEVELS[opts.level.toLowerCase()] !== undefined) opts.level = opts.level.toLowerCase()\n\n  const {\n    redact,\n    crlf,\n    serializers,\n    timestamp,\n    messageKey,\n    errorKey,\n    nestedKey,\n    base,\n    name,\n    level,\n    customLevels,\n    levelComparison,\n    mixin,\n    mixinMergeStrategy,\n    useOnlyCustomLevels,\n    formatters,\n    hooks,\n    depthLimit,\n    edgeLimit,\n    onChild,\n    msgPrefix\n  } = opts\n\n  const stringifySafe = configure({\n    maximumDepth: depthLimit,\n    maximumBreadth: edgeLimit\n  })\n\n  const allFormatters = buildFormatters(\n    formatters.level,\n    formatters.bindings,\n    formatters.log\n  )\n\n  const stringifyFn = stringify.bind({\n    [stringifySafeSym]: stringifySafe\n  })\n  const stringifiers = redact ? redaction(redact, stringifyFn) : {}\n  const formatOpts = redact\n    ? { stringify: stringifiers[redactFmtSym] }\n    : { stringify: stringifyFn }\n  const end = '}' + (crlf ? '\\r\\n' : '\\n')\n  const coreChindings = asChindings.bind(null, {\n    [chindingsSym]: '',\n    [serializersSym]: serializers,\n    [stringifiersSym]: stringifiers,\n    [stringifySym]: stringify,\n    [stringifySafeSym]: stringifySafe,\n    [formattersSym]: allFormatters\n  })\n\n  let chindings = ''\n  if (base !== null) {\n    if (name === undefined) {\n      chindings = coreChindings(base)\n    } else {\n      chindings = coreChindings(Object.assign({}, base, { name }))\n    }\n  }\n\n  const time = (timestamp instanceof Function)\n    ? timestamp\n    : (timestamp ? epochTime : nullTime)\n  const timeSliceIndex = time().indexOf(':') + 1\n\n  if (useOnlyCustomLevels && !customLevels) throw Error('customLevels is required if useOnlyCustomLevels is set true')\n  if (mixin && typeof mixin !== 'function') throw Error(`Unknown mixin type \"${typeof mixin}\" - expected \"function\"`)\n  if (msgPrefix && typeof msgPrefix !== 'string') throw Error(`Unknown msgPrefix type \"${typeof msgPrefix}\" - expected \"string\"`)\n\n  assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels)\n  const levels = mappings(customLevels, useOnlyCustomLevels)\n\n  if (stream && stream[transportUsesMultistreamSym] === true) {\n    let sampleLabel = typeof level === 'string' ? level : undefined\n    if (!sampleLabel || levels[sampleLabel] === undefined) {\n      sampleLabel = Object.keys(levels)[0]\n    }\n    const sampleNumber = levels[sampleLabel]\n    let ok = false\n    try {\n      const formatted = formatters.level(sampleLabel, sampleNumber)\n      ok = formatted && typeof formatted === 'object' && formatted.level === sampleNumber\n    } catch {\n      ok = false\n    }\n\n    if (!ok) {\n      process.emitWarning(\n        'custom formatters.level detected with multiple transport targets/pipelines; ensure logs include a numeric \"level\" field or they may be dropped',\n        { code: 'PINO_TRANSPORT_MULTI_TARGETS_LEVEL_FORMATTER' }\n      )\n    }\n  }\n\n  if (typeof stream.emit === 'function') {\n    stream.emit('message', { code: 'PINO_CONFIG', config: { levels, messageKey, errorKey } })\n  }\n\n  assertLevelComparison(levelComparison)\n  const levelCompFunc = genLevelComparison(levelComparison)\n\n  Object.assign(instance, {\n    levels,\n    [levelCompSym]: levelCompFunc,\n    [useOnlyCustomLevelsSym]: useOnlyCustomLevels,\n    [streamSym]: stream,\n    [timeSym]: time,\n    [timeSliceIndexSym]: timeSliceIndex,\n    [stringifySym]: stringify,\n    [stringifySafeSym]: stringifySafe,\n    [stringifiersSym]: stringifiers,\n    [endSym]: end,\n    [formatOptsSym]: formatOpts,\n    [messageKeySym]: messageKey,\n    [errorKeySym]: errorKey,\n    [nestedKeySym]: nestedKey,\n    // protect against injection\n    [nestedKeyStrSym]: nestedKey ? `,${JSON.stringify(nestedKey)}:{` : '',\n    [serializersSym]: serializers,\n    [mixinSym]: mixin,\n    [mixinMergeStrategySym]: mixinMergeStrategy,\n    [chindingsSym]: chindings,\n    [formattersSym]: allFormatters,\n    [hooksSym]: hooks,\n    silent: noop,\n    onChild,\n    [msgPrefixSym]: msgPrefix\n  })\n\n  Object.setPrototypeOf(instance, proto())\n\n  genLsCache(instance)\n\n  instance[setLevelSym](level)\n\n  return instance\n}\n\nmodule.exports = pino\n\nmodule.exports.destination = (dest = process.stdout.fd) => {\n  if (typeof dest === 'object') {\n    dest.dest = normalizeDestFileDescriptor(dest.dest || process.stdout.fd)\n    return buildSafeSonicBoom(dest)\n  } else {\n    return buildSafeSonicBoom({ dest: normalizeDestFileDescriptor(dest), minLength: 0 })\n  }\n}\n\nmodule.exports.transport = require('./lib/transport')\nmodule.exports.multistream = require('./lib/multistream')\n\nmodule.exports.levels = mappings()\nmodule.exports.stdSerializers = serializers\nmodule.exports.stdTimeFunctions = Object.assign({}, time)\nmodule.exports.symbols = symbols\nmodule.exports.version = version\n\n// Enables default and name export with TypeScript and Babel\nmodule.exports.default = pino\nmodule.exports.pino = pino\n"
  },
  {
    "path": "test/basic.test.js",
    "content": "'use strict'\n\nconst os = require('node:os')\nconst { readFileSync } = require('node:fs')\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, check, match, once, watchFileCreated, file } = require('./helper')\nconst pino = require('../')\nconst { version } = require('../package.json')\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('pino version is exposed on export', () => {\n  assert.equal(pino.version, version)\n})\n\ntest('pino version is exposed on instance', () => {\n  const instance = pino()\n  assert.equal(instance.version, version)\n})\n\ntest('child instance exposes pino version', () => {\n  const child = pino().child({ foo: 'bar' })\n  assert.equal(child.version, version)\n})\n\ntest('bindings are exposed on every instance', () => {\n  const instance = pino()\n  assert.deepEqual(instance.bindings(), {})\n})\n\ntest('bindings contain the name and the child bindings', () => {\n  const instance = pino({ name: 'basicTest', level: 'info' }).child({ foo: 'bar' }).child({ a: 2 })\n  assert.deepEqual(instance.bindings(), { name: 'basicTest', foo: 'bar', a: 2 })\n})\n\ntest('set bindings on instance', () => {\n  const instance = pino({ name: 'basicTest', level: 'info' })\n  instance.setBindings({ foo: 'bar' })\n  assert.deepEqual(instance.bindings(), { name: 'basicTest', foo: 'bar' })\n})\n\ntest('newly set bindings overwrite old bindings', () => {\n  const instance = pino({ name: 'basicTest', level: 'info', base: { foo: 'bar' } })\n  instance.setBindings({ foo: 'baz' })\n  assert.deepEqual(instance.bindings(), { name: 'basicTest', foo: 'baz' })\n})\n\ntest('set bindings on child instance', () => {\n  const child = pino({ name: 'basicTest', level: 'info' }).child({})\n  child.setBindings({ foo: 'bar' })\n  assert.deepEqual(child.bindings(), { name: 'basicTest', foo: 'bar' })\n})\n\ntest('child should have bindings set by parent', () => {\n  const instance = pino({ name: 'basicTest', level: 'info' })\n  instance.setBindings({ foo: 'bar' })\n  const child = instance.child({})\n  assert.deepEqual(child.bindings(), { name: 'basicTest', foo: 'bar' })\n})\n\ntest('child should not share bindings of parent set after child creation', () => {\n  const instance = pino({ name: 'basicTest', level: 'info' })\n  const child = instance.child({})\n  instance.setBindings({ foo: 'bar' })\n  assert.deepEqual(instance.bindings(), { name: 'basicTest', foo: 'bar' })\n  assert.deepEqual(child.bindings(), { name: 'basicTest' })\n})\n\nfunction levelTest (name, level) {\n  test(`${name} logs as ${level}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    instance[name]('hello world')\n    check(assert.equal, await once(stream, 'data'), level, 'hello world')\n  })\n\n  test(`passing objects at level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    const obj = { hello: 'world' }\n    instance[name](obj)\n\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    assert.equal(result.pid, pid)\n    assert.equal(result.hostname, hostname)\n    assert.equal(result.level, level)\n    assert.equal(result.hello, 'world')\n    assert.deepEqual(Object.keys(obj), ['hello'])\n  })\n\n  test(`passing an object and a string at level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    const obj = { hello: 'world' }\n    instance[name](obj, 'a string')\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      msg: 'a string',\n      hello: 'world'\n    })\n    assert.deepEqual(Object.keys(obj), ['hello'])\n  })\n\n  test(`passing a undefined and a string at level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    instance[name](undefined, 'a string')\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      msg: 'a string'\n    })\n  })\n\n  test(`overriding object key by string at level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    instance[name]({ hello: 'world', msg: 'object' }, 'string')\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      msg: 'string',\n      hello: 'world'\n    })\n  })\n\n  test(`formatting logs as ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    instance[name]('hello %d', 42)\n    const result = await once(stream, 'data')\n    check(assert.equal, result, level, 'hello 42')\n  })\n\n  test(`formatting a symbol at level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n\n    const sym = Symbol('foo')\n    instance[name]('hello %s', sym)\n\n    const result = await once(stream, 'data')\n\n    check(assert.equal, result, level, 'hello Symbol(foo)')\n  })\n\n  test(`passing error with a serializer at level ${name}`, async () => {\n    const stream = sink()\n    const err = new Error('myerror')\n    const instance = pino({\n      serializers: {\n        err: pino.stdSerializers.err\n      }\n    }, stream)\n    instance.level = name\n    instance[name]({ err })\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      err: {\n        type: 'Error',\n        message: err.message,\n        stack: err.stack\n      },\n      msg: err.message\n    })\n  })\n\n  test(`child logger for level ${name}`, async () => {\n    const stream = sink()\n    const instance = pino(stream)\n    instance.level = name\n    const child = instance.child({ hello: 'world' })\n    child[name]('hello world')\n    const result = await once(stream, 'data')\n    assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      msg: 'hello world',\n      hello: 'world'\n    })\n  })\n}\n\nlevelTest('fatal', 60)\nlevelTest('error', 50)\nlevelTest('warn', 40)\nlevelTest('info', 30)\nlevelTest('debug', 20)\nlevelTest('trace', 10)\n\ntest('serializers can return undefined to strip field', async () => {\n  const stream = sink()\n  const instance = pino({\n    serializers: {\n      test () { return undefined }\n    }\n  }, stream)\n\n  instance.info({ test: 'sensitive info' })\n  const result = await once(stream, 'data')\n  assert.equal('test' in result, false)\n})\n\ntest('streams receive a message event with PINO_CONFIG', (t, end) => {\n  const stream = sink()\n  stream.once('message', (message) => {\n    match(message, {\n      code: 'PINO_CONFIG',\n      config: {\n        errorKey: 'err',\n        levels: {\n          labels: {\n            10: 'trace',\n            20: 'debug',\n            30: 'info',\n            40: 'warn',\n            50: 'error',\n            60: 'fatal'\n          },\n          values: {\n            debug: 20,\n            error: 50,\n            fatal: 60,\n            info: 30,\n            trace: 10,\n            warn: 40\n          }\n        },\n        messageKey: 'msg'\n      }\n    })\n    end()\n  })\n  pino(stream)\n})\n\ntest('does not explode with a circular ref', () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const b = {}\n  const a = {\n    hello: b\n  }\n  b.a = a // circular ref\n  assert.doesNotThrow(() => instance.info(a))\n})\n\ntest('set the name', async () => {\n  const stream = sink()\n  const instance = pino({\n    name: 'hello'\n  }, stream)\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    name: 'hello',\n    msg: 'this is fatal'\n  })\n})\n\ntest('set the messageKey', async () => {\n  const stream = sink()\n  const message = 'hello world'\n  const messageKey = 'fooMessage'\n  const instance = pino({\n    messageKey\n  }, stream)\n  instance.info(message)\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    fooMessage: message\n  })\n})\n\ntest('set the nestedKey', async () => {\n  const stream = sink()\n  const object = { hello: 'world' }\n  const nestedKey = 'stuff'\n  const instance = pino({\n    nestedKey\n  }, stream)\n  instance.info(object)\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    stuff: object\n  })\n})\n\ntest('set undefined properties', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info({ hello: 'world', property: undefined })\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    hello: 'world'\n  })\n})\n\ntest('prototype properties are not logged', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info(Object.create({ hello: 'world' }))\n  const { hello } = await once(stream, 'data')\n  assert.equal(hello, undefined)\n})\n\ntest('set the base', async () => {\n  const stream = sink()\n  const instance = pino({\n    base: {\n      a: 'b'\n    }\n  }, stream)\n\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    a: 'b',\n    level: 60,\n    msg: 'this is fatal'\n  })\n})\n\ntest('set the base to null', async () => {\n  const stream = sink()\n  const instance = pino({\n    base: null\n  }, stream)\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    level: 60,\n    msg: 'this is fatal'\n  })\n})\n\ntest('set the base to null and use a formatter', async () => {\n  const stream = sink()\n  const instance = pino({\n    base: null,\n    formatters: {\n      log (input) {\n        return Object.assign({}, input, { additionalMessage: 'using pino' })\n      }\n    }\n  }, stream)\n  instance.fatal('this is fatal too')\n  const result = await once(stream, 'data')\n  assert.equal(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    level: 60,\n    msg: 'this is fatal too',\n    additionalMessage: 'using pino'\n  })\n})\n\ntest('throw if creating child without bindings', () => {\n  const stream = sink()\n  const instance = pino(stream)\n  try {\n    instance.child()\n    assert.fail('it should throw')\n  } catch (err) {\n    assert.equal(err.message, 'missing bindings for child Pino')\n  }\n})\n\ntest('correctly escapes msg strings with stray double quote at end', async () => {\n  const stream = sink()\n  const instance = pino({\n    name: 'hello'\n  }, stream)\n\n  instance.fatal('this contains \"')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    name: 'hello',\n    msg: 'this contains \"'\n  })\n})\n\ntest('correctly escape msg strings with unclosed double quote', async () => {\n  const stream = sink()\n  const instance = pino({\n    name: 'hello'\n  }, stream)\n  instance.fatal('\" this contains')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    name: 'hello',\n    msg: '\" this contains'\n  })\n})\n\ntest('correctly escape quote in a key', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const obj = { 'some\"obj': 'world' }\n  instance.info(obj, 'a string')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    level: 30,\n    pid,\n    hostname,\n    msg: 'a string',\n    'some\"obj': 'world'\n  })\n  assert.deepEqual(Object.keys(obj), ['some\"obj'])\n})\n\n// https://github.com/pinojs/pino/issues/139\ntest('object and format string', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info({}, 'foo %s', 'bar')\n\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'foo bar'\n  })\n})\n\ntest('object and format string property', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info({ answer: 42 }, 'foo %s', 'bar')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'foo bar',\n    answer: 42\n  })\n})\n\ntest('correctly strip undefined when returned from toJSON', async () => {\n  const stream = sink()\n  const instance = pino({\n    test: 'this'\n  }, stream)\n  instance.fatal({ test: { toJSON () { return undefined } } })\n  const result = await once(stream, 'data')\n  assert.equal('test' in result, false)\n})\n\ntest('correctly supports stderr', (t, end) => {\n  // stderr inherits from Stream, rather than Writable\n  const dest = {\n    writable: true,\n    write (result) {\n      result = JSON.parse(result)\n      delete result.time\n      assert.deepEqual(result, {\n        pid,\n        hostname,\n        level: 60,\n        msg: 'a message'\n      })\n      end()\n    }\n  }\n  const instance = pino(dest)\n  instance.fatal('a message')\n})\n\ntest('normalize number to string', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info(1)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: '1'\n  })\n})\n\ntest('normalize number to string with an object', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info({ answer: 42 }, 1)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: '1',\n    answer: 42\n  })\n})\n\ntest('handles objects with null prototype', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const o = Object.create(null)\n  o.test = 'test'\n  instance.info(o)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    test: 'test'\n  })\n})\n\ntest('pino.destination', async () => {\n  const tmp = file()\n  const instance = pino(pino.destination(tmp))\n  instance.info('hello')\n  await watchFileCreated(tmp)\n  const result = JSON.parse(readFileSync(tmp).toString())\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('auto pino.destination with a string', async () => {\n  const tmp = file()\n  const instance = pino(tmp)\n  instance.info('hello')\n  await watchFileCreated(tmp)\n  const result = JSON.parse(readFileSync(tmp).toString())\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('auto pino.destination with a string as second argument', async () => {\n  const tmp = file()\n  const instance = pino(null, tmp)\n  instance.info('hello')\n  await watchFileCreated(tmp)\n  const result = JSON.parse(readFileSync(tmp).toString())\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('does not override opts with a string as second argument', async () => {\n  const tmp = file()\n  const instance = pino({\n    timestamp: () => ',\"time\":\"none\"'\n  }, tmp)\n  instance.info('hello')\n  await watchFileCreated(tmp)\n  const result = JSON.parse(readFileSync(tmp).toString())\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    time: 'none',\n    msg: 'hello'\n  })\n})\n\n// https://github.com/pinojs/pino/issues/222\ntest('children with same names render in correct order', async () => {\n  const stream = sink()\n  const root = pino(stream)\n  root.child({ a: 1 }).child({ a: 2 }).info({ a: 3 })\n  const { a } = await once(stream, 'data')\n  assert.equal(a, 3, 'last logged object takes precedence')\n})\n\ntest('use `safe-stable-stringify` to avoid circular dependencies', async () => {\n  const stream = sink()\n  const root = pino(stream)\n  // circular depth\n  const obj = {}\n  obj.a = obj\n  root.info(obj)\n  const { a } = await once(stream, 'data')\n  assert.deepEqual(a, { a: '[Circular]' })\n})\n\ntest('correctly log non circular objects', async () => {\n  const stream = sink()\n  const root = pino(stream)\n  const obj = {}\n  let parent = obj\n  for (let i = 0; i < 10; i++) {\n    parent.node = {}\n    parent = parent.node\n  }\n  root.info(obj)\n  const { node } = await once(stream, 'data')\n  assert.deepEqual(node, { node: { node: { node: { node: { node: { node: { node: { node: { node: {} } } } } } } } } })\n})\n\ntest('safe-stable-stringify must be used when interpolating', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { a: { b: {} } }\n  o.a.b.c = o.a.b\n  instance.info('test %j', o)\n\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'test {\"a\":{\"b\":{\"c\":\"[Circular]\"}}}')\n})\n\ntest('throws when setting useOnlyCustomLevels without customLevels', () => {\n  assert.throws(\n    () => {\n      pino({\n        useOnlyCustomLevels: true\n      })\n    },\n    /customLevels is required if useOnlyCustomLevels is set true/\n  )\n})\n\ntest('correctly log Infinity', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: Infinity }\n  instance.info(o)\n\n  const { num } = await once(stream, 'data')\n  assert.equal(num, null)\n})\n\ntest('correctly log -Infinity', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: -Infinity }\n  instance.info(o)\n\n  const { num } = await once(stream, 'data')\n  assert.equal(num, null)\n})\n\ntest('correctly log NaN', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: NaN }\n  instance.info(o)\n\n  const { num } = await once(stream, 'data')\n  assert.equal(num, null)\n})\n\ntest('offers a .default() method to please typescript', async () => {\n  assert.equal(pino.default, pino)\n\n  const stream = sink()\n  const instance = pino.default(stream)\n  instance.info('hello world')\n  check(assert.equal, await once(stream, 'data'), 30, 'hello world')\n})\n\ntest('correctly skip function', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: NaN }\n  instance.info(o, () => {})\n\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, undefined)\n})\n\ntest('correctly skip Infinity', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: NaN }\n  instance.info(o, Infinity)\n\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, null)\n})\n\ntest('correctly log number', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n\n  const o = { num: NaN }\n  instance.info(o, 42)\n\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 42)\n})\n\ntest('nestedKey should not be used for non-objects', async () => {\n  const stream = sink()\n  const message = 'hello'\n  const nestedKey = 'stuff'\n  const instance = pino({\n    nestedKey\n  }, stream)\n  instance.info(message)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepStrictEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: message\n  })\n})\n\ntest('throws if prettyPrint is passed in as an option', async () => {\n  assert.throws(\n    () => {\n      pino({\n        prettyPrint: true\n      })\n    },\n    Error('prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)')\n  )\n})\n\ntest('Should invoke `onChild` with the newly created child', () => {\n  let innerChild\n  const child = pino({\n    onChild: (instance) => {\n      innerChild = instance\n    }\n  }).child({ foo: 'bar' })\n  assert.equal(child, innerChild)\n})\n\ntest('logger message should have the prefix message that defined in the logger creation', async () => {\n  const stream = sink()\n  const logger = pino({\n    msgPrefix: 'My name is Bond '\n  }, stream)\n  assert.equal(logger.msgPrefix, 'My name is Bond ')\n  logger.info('James Bond')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n\ntest('child message should have the prefix message that defined in the child creation', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const child = instance.child({}, { msgPrefix: 'My name is Bond ' })\n  child.info('James Bond')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n\ntest('child message should have the prefix message that defined in the child creation when logging with log meta', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const child = instance.child({}, { msgPrefix: 'My name is Bond ' })\n  child.info({ hello: 'world' }, 'James Bond')\n  const { msg, hello } = await once(stream, 'data')\n  assert.equal(hello, 'world')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n\ntest('logged message should not have the prefix when not providing any message', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const child = instance.child({}, { msgPrefix: 'This should not be shown ' })\n  child.info({ hello: 'world' })\n  const { msg, hello } = await once(stream, 'data')\n  assert.equal(hello, 'world')\n  assert.equal(msg, undefined)\n})\n\ntest('child message should append parent prefix to current prefix that defined in the child creation', async () => {\n  const stream = sink()\n  const instance = pino({\n    msgPrefix: 'My name is Bond '\n  }, stream)\n  const child = instance.child({}, { msgPrefix: 'James ' })\n  child.info('Bond')\n  assert.equal(child.msgPrefix, 'My name is Bond James ')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n\ntest('child message should inherent parent prefix', async () => {\n  const stream = sink()\n  const instance = pino({\n    msgPrefix: 'My name is Bond '\n  }, stream)\n  const child = instance.child({})\n  child.info('James Bond')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n\ntest('grandchild message should inherent parent prefix', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  const child = instance.child({}, { msgPrefix: 'My name is Bond ' })\n  const grandchild = child.child({})\n  grandchild.info('James Bond')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'My name is Bond James Bond')\n})\n"
  },
  {
    "path": "test/broken-pipe.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { fork } = require('node:child_process')\nconst tspl = require('@matteo.collina/tspl')\nconst { once } = require('./helper')\nconst pino = require('..')\n\nif (process.platform === 'win32') {\n  console.log('skipping on windows')\n  process.exit(0)\n}\n\nif (process.env.CITGM) {\n  // This looks like a some form of limitations of the CITGM test runner\n  // or the HW/SW we run it on. This file can hang on Node.js v18.x.\n  // The failure does not reproduce locally or on our CI.\n  // Skipping it is the only way to keep pino in CITGM.\n  // https://github.com/nodejs/citgm/pull/1002#issuecomment-1751942988\n  console.log('Skipping on Node.js core CITGM because it hangs on v18.x')\n  process.exit(0)\n}\n\nfunction testFile (file) {\n  file = join('fixtures', 'broken-pipe', file)\n  test(file, async () => {\n    const child = fork(join(__dirname, file), { silent: true })\n    child.stdout.destroy()\n\n    child.stderr.pipe(process.stdout)\n\n    const res = await once(child, 'close')\n    assert.equal(res, 0) // process exits successfully\n  })\n}\n\ntestFile('basic.js')\ntestFile('destination.js')\ntestFile('syncfalse.js')\n\ntest('let error pass through', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = pino.destination({ sync: true })\n\n  // side effect of the pino constructor is that it will set an\n  // event handler for error\n  pino(stream)\n\n  process.nextTick(() => stream.emit('error', new Error('kaboom')))\n  process.nextTick(() => stream.emit('error', new Error('kaboom')))\n\n  stream.on('error', (err) => {\n    plan.equal(err.message, 'kaboom')\n  })\n\n  await plan\n})\n"
  },
  {
    "path": "test/browser-child.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst pino = require('../browser')\n\ntest('child has parent level', ({ end, same, is }) => {\n  const instance = pino({\n    level: 'error',\n    browser: {}\n  })\n\n  const child = instance.child({})\n\n  same(child.level, instance.level)\n  end()\n})\n\ntest('child can set level at creation time', ({ end, same, is }) => {\n  const instance = pino({\n    level: 'error',\n    browser: {}\n  })\n\n  const child = instance.child({}, { level: 'info' }) // first bindings, then options\n\n  same(child.level, 'info')\n  end()\n})\n\ntest('changing child level does not affect parent', ({ end, same, is }) => {\n  const instance = pino({\n    level: 'error',\n    browser: {}\n  })\n\n  const child = instance.child({})\n  child.level = 'info'\n\n  same(instance.level, 'error')\n  end()\n})\n\ntest('child should log, if its own level allows it', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 30,\n      msg: 'this is info'\n    },\n    {\n      level: 40,\n      msg: 'this is warn'\n    },\n    {\n      level: 50,\n      msg: 'this is an error'\n    }\n  ]\n  const instance = pino({\n    level: 'error',\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  const child = instance.child({})\n  child.level = 'info'\n\n  child.debug('this is debug')\n  child.info('this is info')\n  child.warn('this is warn')\n  child.error('this is an error')\n\n  same(expected.length, 0, 'not all messages were read')\n  end()\n})\n\ntest('changing child log level should not affect parent log behavior', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    level: 'error',\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  const child = instance.child({})\n  child.level = 'info'\n\n  instance.warn('this is warn')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  same(expected.length, 0, 'not all messages were read')\n  end()\n})\n\ntest('onChild callback should be called when new child is created', ({ end, pass, plan }) => {\n  plan(1)\n  const instance = pino({\n    level: 'error',\n    browser: {},\n    onChild: (_child) => {\n      pass('onChild callback was called')\n      end()\n    }\n  })\n\n  instance.child({})\n})\n\nfunction checkLogObjects (is, same, actual, expected) {\n  is(actual.time <= Date.now(), true, 'time is greater than Date.now()')\n\n  const actualCopy = Object.assign({}, actual)\n  const expectedCopy = Object.assign({}, expected)\n  delete actualCopy.time\n  delete expectedCopy.time\n\n  same(actualCopy, expectedCopy)\n}\n"
  },
  {
    "path": "test/browser-disabled.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst pino = require('../browser')\n\ntest('set browser opts disabled to true', ({ end, same }) => {\n  const instance = pino({\n    browser: {\n      disabled: true,\n      write (actual) {\n        checkLogObjects(same, actual, [])\n      }\n    }\n  })\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('set browser opts disabled to false', ({ end, same }) => {\n  const expected = [\n    {\n      level: 30,\n      msg: 'hello world'\n    },\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    browser: {\n      disabled: false,\n      write (actual) {\n        checkLogObjects(same, actual, expected.shift())\n      }\n    }\n  })\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('disabled is not set in browser opts', ({ end, same }) => {\n  const expected = [\n    {\n      level: 30,\n      msg: 'hello world'\n    },\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    browser: {\n      write (actual) {\n        checkLogObjects(same, actual, expected.shift())\n      }\n    }\n  })\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\nfunction checkLogObjects (same, actual, expected, is) {\n  const actualCopy = Object.assign({}, actual)\n  const expectedCopy = Object.assign({}, expected)\n  delete actualCopy.time\n  delete expectedCopy.time\n\n  same(actualCopy, expectedCopy)\n}\n"
  },
  {
    "path": "test/browser-early-console-freeze.test.js",
    "content": "'use strict'\nObject.freeze(console)\nconst test = require('tape')\nconst pino = require('../browser')\n\ntest('silent level', ({ end, fail, pass }) => {\n  pino({\n    level: 'silent',\n    browser: { }\n  })\n  end()\n})\n"
  },
  {
    "path": "test/browser-is-level-enabled.test.js",
    "content": "'use strict'\n\nconst { describe, test } = require('node:test')\nconst assert = require('node:assert')\nconst pino = require('../browser')\n\nconst customLevels = {\n  trace: 10,\n  debug: 20,\n  info: 30,\n  warn: 40,\n  error: 50,\n  fatal: 60\n}\n\ndescribe('Default levels suite', () => {\n  test('can check if current level enabled', async () => {\n    const log = pino({ level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if current level enabled when as object', async () => {\n    const log = pino({ asObject: true, level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if level enabled after level set', async () => {\n    const log = pino()\n    assert.equal(false, log.isLevelEnabled('debug'))\n    log.level = 'debug'\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if higher level enabled', async () => {\n    const log = pino({ level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('error'))\n  })\n\n  test('can check if lower level is disabled', async () => {\n    const log = pino({ level: 'error' })\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('ASC: can check if child has current level enabled', async () => {\n    const log = pino().child({}, { level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if custom level is enabled', async () => {\n    const log = pino({\n      customLevels: { foo: 35 },\n      level: 'debug'\n    })\n    assert.equal(true, log.isLevelEnabled('foo'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n})\n\ndescribe('Custom levels suite', () => {\n  test('can check if current level enabled', async () => {\n    const log = pino({ level: 'debug', customLevels })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if level enabled after level set', async () => {\n    const log = pino({ customLevels })\n    assert.equal(false, log.isLevelEnabled('debug'))\n    log.level = 'debug'\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if higher level enabled', async () => {\n    const log = pino({ level: 'debug', customLevels })\n    assert.equal(true, log.isLevelEnabled('error'))\n  })\n\n  test('can check if lower level is disabled', async () => {\n    const log = pino({ level: 'error', customLevels })\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if child has current level enabled', async () => {\n    const log = pino().child({ customLevels }, { level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if custom level is enabled', async () => {\n    const log = pino({\n      customLevels: { foo: 35, ...customLevels },\n      level: 'debug'\n    })\n    assert.equal(true, log.isLevelEnabled('foo'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n})\n"
  },
  {
    "path": "test/browser-levels.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst pino = require('../browser')\n\ntest('set the level by string', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  instance.level = 'error'\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('set the level by string. init with silent', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    level: 'silent',\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  instance.level = 'error'\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('set the level by string. init with silent and transmit', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    level: 'silent',\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    },\n    transmit: {\n      send () {}\n    }\n  })\n\n  instance.level = 'error'\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('set the level via constructor', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 50,\n      msg: 'this is an error'\n    },\n    {\n      level: 60,\n      msg: 'this is fatal'\n    }\n  ]\n  const instance = pino({\n    level: 'error',\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  end()\n})\n\ntest('set custom level and use it', ({ end, same, is }) => {\n  const expected = [\n    {\n      level: 31,\n      msg: 'this is a custom level'\n    }\n  ]\n  const instance = pino({\n    customLevels: {\n      success: 31\n    },\n    browser: {\n      write (actual) {\n        checkLogObjects(is, same, actual, expected.shift())\n      }\n    }\n  })\n\n  instance.success('this is a custom level')\n\n  end()\n})\n\ntest('the wrong level throws', ({ end, throws }) => {\n  const instance = pino()\n  throws(() => {\n    instance.level = 'kaboom'\n  })\n  end()\n})\n\ntest('the wrong level by number throws', ({ end, throws }) => {\n  const instance = pino()\n  throws(() => {\n    instance.levelVal = 55\n  })\n  end()\n})\n\ntest('exposes level string mappings', ({ end, is }) => {\n  is(pino.levels.values.error, 50)\n  end()\n})\n\ntest('exposes level number mappings', ({ end, is }) => {\n  is(pino.levels.labels[50], 'error')\n  end()\n})\n\ntest('returns level integer', ({ end, is }) => {\n  const instance = pino({ level: 'error' })\n  is(instance.levelVal, 50)\n  end()\n})\n\ntest('silent level via constructor', ({ end, fail }) => {\n  const instance = pino({\n    level: 'silent',\n    browser: {\n      write () {\n        fail('no data should be logged')\n      }\n    }\n  })\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    instance[level]('hello world')\n  })\n\n  end()\n})\n\ntest('silent level by string', ({ end, fail }) => {\n  const instance = pino({\n    browser: {\n      write () {\n        fail('no data should be logged')\n      }\n    }\n  })\n\n  instance.level = 'silent'\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    instance[level]('hello world')\n  })\n\n  end()\n})\n\ntest('exposed levels', ({ end, same }) => {\n  same(Object.keys(pino.levels.values), [\n    'fatal',\n    'error',\n    'warn',\n    'info',\n    'debug',\n    'trace'\n  ])\n  end()\n})\n\ntest('exposed labels', ({ end, same }) => {\n  same(Object.keys(pino.levels.labels), [\n    '10',\n    '20',\n    '30',\n    '40',\n    '50',\n    '60'\n  ])\n  end()\n})\n\nfunction checkLogObjects (is, same, actual, expected) {\n  is(actual.time <= Date.now(), true, 'time is greater than Date.now()')\n\n  const actualCopy = Object.assign({}, actual)\n  const expectedCopy = Object.assign({}, expected)\n  delete actualCopy.time\n  delete expectedCopy.time\n\n  same(actualCopy, expectedCopy)\n}\n"
  },
  {
    "path": "test/browser-redaction.test.js",
    "content": "'use strict'\n// eslint-disable-next-line\nif (typeof $1 !== 'undefined') $1 = arguments.callee.caller.arguments[0]\n\nconst test = require('tape')\nconst pino = require('../browser')\n\ntest('redact option as array redacts specified paths', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.password, '[Redacted]')\n        is(o.username, 'john')\n        end()\n      }\n    },\n    redact: ['password']\n  })\n\n  instance.info({ password: 'secret', username: 'john' })\n})\n\ntest('redact option as object with custom censor', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.secret, '***HIDDEN***')\n        is(o.visible, 'data')\n        end()\n      }\n    },\n    redact: {\n      paths: ['secret'],\n      censor: '***HIDDEN***'\n    }\n  })\n\n  instance.info({ secret: 'sensitive', visible: 'data' })\n})\n\ntest('redact nested paths', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.user.password, '[Redacted]')\n        is(o.user.name, 'alice')\n        end()\n      }\n    },\n    redact: ['user.password']\n  })\n\n  instance.info({ user: { name: 'alice', password: 'secret123' } })\n})\n\ntest('redact with wildcard paths', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.items[0].secret, '[Redacted]')\n        is(o.items[1].secret, '[Redacted]')\n        is(o.items[0].id, 1)\n        is(o.items[1].id, 2)\n        end()\n      }\n    },\n    redact: ['items[*].secret']\n  })\n\n  instance.info({\n    items: [\n      { id: 1, secret: 'a' },\n      { id: 2, secret: 'b' }\n    ]\n  })\n})\n\ntest('redact with remove option removes the key entirely', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.removeMe, undefined)\n        is(o.keepMe, 'visible')\n        end()\n      }\n    },\n    redact: {\n      paths: ['removeMe'],\n      remove: true\n    }\n  })\n\n  instance.info({ removeMe: 'gone', keepMe: 'visible' })\n})\n\ntest('redact throws on invalid paths option', ({ end, throws }) => {\n  throws(() => {\n    pino({\n      browser: { asObject: true },\n      redact: { paths: 'not-an-array' }\n    })\n  }, /pino – redact must contain an array of strings/)\n  end()\n})\n\ntest('redact works with child loggers', ({ end, is }) => {\n  const parent = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.password, '[Redacted]')\n        is(o.childBinding, 'value')\n        end()\n      }\n    },\n    redact: ['password']\n  })\n\n  const child = parent.child({ childBinding: 'value' })\n  child.info({ password: 'secret' })\n})\n\ntest('redact multiple paths', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.password, '[Redacted]')\n        is(o.creditCard, '[Redacted]')\n        is(o.ssn, '[Redacted]')\n        is(o.name, 'bob')\n        end()\n      }\n    },\n    redact: ['password', 'creditCard', 'ssn']\n  })\n\n  instance.info({\n    password: 'secret',\n    creditCard: '1234-5678-9012-3456',\n    ssn: '123-45-6789',\n    name: 'bob'\n  })\n})\n\ntest('redact with bracket notation for hyphenated keys', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o['api-key'], '[Redacted]')\n        is(o.name, 'test')\n        end()\n      }\n    },\n    redact: ['[\"api-key\"]']\n  })\n\n  instance.info({ 'api-key': 'sensitive', name: 'test' })\n})\n\ntest('redact works with asObjectBindingsOnly mode', ({ end, is, deepEqual }) => {\n  const instance = pino({\n    browser: {\n      asObjectBindingsOnly: true,\n      write (o, ...args) {\n        is(o.password, '[Redacted]')\n        is(o.username, 'john')\n        deepEqual(args, ['remaining', 'args'])\n        end()\n      }\n    },\n    redact: ['password']\n  })\n\n  instance.info({ password: 'secret', username: 'john' }, 'remaining', 'args')\n})\n\ntest('redact works with asObjectBindingsOnly mode and object message', ({ end, is, ok }) => {\n  const instance = pino({\n    browser: {\n      asObjectBindingsOnly: true,\n      write (o, ...args) {\n        is(o.password, '[Redacted]')\n        is(o.foo, 'bar')\n        ok(o.time)\n        is(args.length, 0)\n        end()\n      }\n    },\n    redact: ['password']\n  })\n\n  instance.info({ password: 'secret', foo: 'bar' })\n})\n\ntest('redact with asObjectBindingsOnly and child logger merges multiple bindings', ({ end, is, ok }) => {\n  const parent = pino({\n    browser: {\n      asObjectBindingsOnly: true,\n      write (o, ...args) {\n        is(o.password, '[Redacted]')\n        is(o.parentBinding, 'parent')\n        is(o.childBinding, 'child')\n        is(o.logData, 'value')\n        ok(o.time)\n        end()\n      }\n    },\n    redact: ['password']\n  })\n\n  const child = parent.child({ parentBinding: 'parent' }).child({ childBinding: 'child' })\n  child.info({ logData: 'value', password: 'secret' })\n})\n\ntest('formatters.level works with asObject mode', ({ end, is, ok }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.levelLabel, 'info')\n        is(o.levelValue, 30)\n        is(o.msg, 'test message')\n        ok(o.time)\n        end()\n      },\n      formatters: {\n        level (label, number) {\n          return { levelLabel: label, levelValue: number }\n        }\n      }\n    }\n  })\n\n  instance.info('test message')\n})\n\ntest('formatters.level with asObject and object message', ({ end, is, ok }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write (o) {\n        is(o.levelLabel, 'warn')\n        is(o.levelValue, 40)\n        is(o.data, 'value')\n        ok(o.time)\n        end()\n      },\n      formatters: {\n        level (label, number) {\n          return { levelLabel: label, levelValue: number }\n        }\n      }\n    }\n  })\n\n  instance.warn({ data: 'value' })\n})\n"
  },
  {
    "path": "test/browser-serializers.test.js",
    "content": "'use strict'\n// eslint-disable-next-line\nif (typeof $1 !== 'undefined') $1 = arguments.callee.caller.arguments[0]\n\nconst test = require('tape')\nconst fresh = require('import-fresh')\nconst pino = require('../browser')\n\nconst parentSerializers = {\n  test: () => 'parent'\n}\n\nconst childSerializers = {\n  test: () => 'child'\n}\n\ntest('serializers override values', ({ end, is }) => {\n  const parent = pino({\n    serializers: parentSerializers,\n    browser: {\n      serialize: true,\n      write (o) {\n        is(o.test, 'parent')\n        end()\n      }\n    }\n  })\n\n  parent.fatal({ test: 'test' })\n})\n\ntest('without the serialize option, serializers do not override values', ({ end, is }) => {\n  const parent = pino({\n    serializers: parentSerializers,\n    browser: {\n      write (o) {\n        is(o.test, 'test')\n        end()\n      }\n    }\n  })\n\n  parent.fatal({ test: 'test' })\n})\n\nif (process.title !== 'browser') {\n  test('if serialize option is true, standard error serializer is auto enabled', ({ end, same }) => {\n    const err = Error('test')\n    err.code = 'test'\n    err.type = 'Error' // get that cov\n    const expect = pino.stdSerializers.err(err)\n\n    const consoleError = console.error\n    console.error = function (err) {\n      same(err, expect)\n    }\n\n    const logger = fresh('../browser')({\n      browser: { serialize: true }\n    })\n\n    console.error = consoleError\n\n    logger.fatal(err)\n    end()\n  })\n\n  test('if serialize option is array, standard error serializer is auto enabled', ({ end, same }) => {\n    const err = Error('test')\n    err.code = 'test'\n    const expect = pino.stdSerializers.err(err)\n\n    const consoleError = console.error\n    console.error = function (err) {\n      same(err, expect)\n    }\n\n    const logger = fresh('../browser', require)({\n      browser: { serialize: [] }\n    })\n\n    console.error = consoleError\n\n    logger.fatal(err)\n    end()\n  })\n\n  test('if serialize option is array containing !stdSerializers.err, standard error serializer is disabled', ({ end, is }) => {\n    const err = Error('test')\n    err.code = 'test'\n    const expect = err\n\n    const consoleError = console.error\n    console.error = function (err) {\n      is(err, expect)\n    }\n\n    const logger = fresh('../browser', require)({\n      browser: { serialize: ['!stdSerializers.err'] }\n    })\n\n    console.error = consoleError\n\n    logger.fatal(err)\n    end()\n  })\n\n  test('in browser, serializers apply to all objects', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (test, test2, test3, test4, test5) {\n      is(test.key, 'serialized')\n      is(test2.key2, 'serialized2')\n      is(test5.key3, 'serialized3')\n    }\n\n    const logger = fresh('../browser', require)({\n      serializers: {\n        key: () => 'serialized',\n        key2: () => 'serialized2',\n        key3: () => 'serialized3'\n      },\n      browser: { serialize: true }\n    })\n\n    console.error = consoleError\n\n    logger.fatal({ key: 'test' }, { key2: 'test' }, 'str should skip', [{ foo: 'array should skip' }], { key3: 'test' })\n    end()\n  })\n\n  test('serialize can be an array of selected serializers', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (test, test2, test3, test4, test5) {\n      is(test.key, 'test')\n      is(test2.key2, 'serialized2')\n      is(test5.key3, 'test')\n    }\n\n    const logger = fresh('../browser', require)({\n      serializers: {\n        key: () => 'serialized',\n        key2: () => 'serialized2',\n        key3: () => 'serialized3'\n      },\n      browser: { serialize: ['key2'] }\n    })\n\n    console.error = consoleError\n\n    logger.fatal({ key: 'test' }, { key2: 'test' }, 'str should skip', [{ foo: 'array should skip' }], { key3: 'test' })\n    end()\n  })\n\n  test('serialize filter applies to child loggers', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (binding, test, test2, test3, test4, test5) {\n      is(test.key, 'test')\n      is(test2.key2, 'serialized2')\n      is(test5.key3, 'test')\n    }\n\n    const logger = fresh('../browser', require)({\n      browser: { serialize: ['key2'] }\n    })\n\n    console.error = consoleError\n\n    logger.child({\n      aBinding: 'test'\n    }, {\n      serializers: {\n        key: () => 'serialized',\n        key2: () => 'serialized2',\n        key3: () => 'serialized3'\n      }\n    }).fatal({ key: 'test' }, { key2: 'test' }, 'str should skip', [{ foo: 'array should skip' }], { key3: 'test' })\n    end()\n  })\n\n  test('serialize filter applies to child loggers through bindings', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (binding, test, test2, test3, test4, test5) {\n      is(test.key, 'test')\n      is(test2.key2, 'serialized2')\n      is(test5.key3, 'test')\n    }\n\n    const logger = fresh('../browser', require)({\n      browser: { serialize: ['key2'] }\n    })\n\n    console.error = consoleError\n\n    logger.child({\n      aBinding: 'test',\n      serializers: {\n        key: () => 'serialized',\n        key2: () => 'serialized2',\n        key3: () => 'serialized3'\n      }\n    }).fatal({ key: 'test' }, { key2: 'test' }, 'str should skip', [{ foo: 'array should skip' }], { key3: 'test' })\n    end()\n  })\n\n  test('parent serializers apply to child bindings', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (binding) {\n      is(binding.key, 'serialized')\n    }\n\n    const logger = fresh('../browser', require)({\n      serializers: {\n        key: () => 'serialized'\n      },\n      browser: { serialize: true }\n    })\n\n    console.error = consoleError\n\n    logger.child({ key: 'test' }).fatal({ test: 'test' })\n    end()\n  })\n\n  test('child serializers apply to child bindings', ({ end, is }) => {\n    const consoleError = console.error\n    console.error = function (binding) {\n      is(binding.key, 'serialized')\n    }\n\n    const logger = fresh('../browser', require)({\n      browser: { serialize: true }\n    })\n\n    console.error = consoleError\n\n    logger.child({\n      key: 'test'\n    }, {\n      serializers: {\n        key: () => 'serialized'\n      }\n    }).fatal({ test: 'test' })\n    end()\n  })\n}\n\ntest('child does not overwrite parent serializers', ({ end, is }) => {\n  let c = 0\n  const parent = pino({\n    serializers: parentSerializers,\n    browser: {\n      serialize: true,\n      write (o) {\n        c++\n        if (c === 1) is(o.test, 'parent')\n        if (c === 2) {\n          is(o.test, 'child')\n          end()\n        }\n      }\n    }\n  })\n  const child = parent.child({}, { serializers: childSerializers })\n\n  parent.fatal({ test: 'test' })\n  child.fatal({ test: 'test' })\n})\n\ntest('children inherit parent serializers', ({ end, is }) => {\n  const parent = pino({\n    serializers: parentSerializers,\n    browser: {\n      serialize: true,\n      write (o) {\n        is(o.test, 'parent')\n      }\n    }\n  })\n\n  const child = parent.child({ a: 'property' })\n  child.fatal({ test: 'test' })\n  end()\n})\n\ntest('children serializers get called', ({ end, is }) => {\n  const parent = pino({\n    browser: {\n      serialize: true,\n      write (o) {\n        is(o.test, 'child')\n      }\n    }\n  })\n\n  const child = parent.child({ a: 'property' }, { serializers: childSerializers })\n\n  child.fatal({ test: 'test' })\n  end()\n})\n\ntest('children serializers get called when inherited from parent', ({ end, is }) => {\n  const parent = pino({\n    serializers: parentSerializers,\n    browser: {\n      serialize: true,\n      write: (o) => {\n        is(o.test, 'pass')\n      }\n    }\n  })\n\n  const child = parent.child({}, { serializers: { test: () => 'pass' } })\n\n  child.fatal({ test: 'fail' })\n  end()\n})\n\ntest('non overridden serializers are available in the children', ({ end, is }) => {\n  const pSerializers = {\n    onlyParent: () => 'parent',\n    shared: () => 'parent'\n  }\n\n  const cSerializers = {\n    shared: () => 'child',\n    onlyChild: () => 'child'\n  }\n\n  let c = 0\n\n  const parent = pino({\n    serializers: pSerializers,\n    browser: {\n      serialize: true,\n      write (o) {\n        c++\n        if (c === 1) is(o.shared, 'child')\n        if (c === 2) is(o.onlyParent, 'parent')\n        if (c === 3) is(o.onlyChild, 'child')\n        if (c === 4) is(o.onlyChild, 'test')\n      }\n    }\n  })\n\n  const child = parent.child({}, { serializers: cSerializers })\n\n  child.fatal({ shared: 'test' })\n  child.fatal({ onlyParent: 'test' })\n  child.fatal({ onlyChild: 'test' })\n  parent.fatal({ onlyChild: 'test' })\n  end()\n})\n"
  },
  {
    "path": "test/browser-timestamp.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst pino = require('../browser')\n\nDate.now = () => 1599400603614\n\ntest('null timestamp', ({ end, is }) => {\n  const instance = pino({\n    timestamp: pino.stdTimeFunctions.nullTime,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, undefined)\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n\ntest('iso timestamp', ({ end, is }) => {\n  const instance = pino({\n    timestamp: pino.stdTimeFunctions.isoTime,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, '2020-09-06T13:56:43.614Z')\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n\ntest('epoch timestamp', ({ end, is }) => {\n  const instance = pino({\n    timestamp: pino.stdTimeFunctions.epochTime,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, 1599400603614)\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n\ntest('unix timestamp', ({ end, is }) => {\n  const instance = pino({\n    timestamp: pino.stdTimeFunctions.unixTime,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, Math.round(1599400603614 / 1000.0))\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n\ntest('epoch timestamp by default', ({ end, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, 1599400603614)\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n\ntest('not print timestamp if the option is false', ({ end, is }) => {\n  const instance = pino({\n    timestamp: false,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.time, undefined)\n      }\n    }\n  })\n  instance.info('hello world')\n  end()\n})\n"
  },
  {
    "path": "test/browser-transmit.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst pino = require('../browser')\n\nfunction noop () {}\n\ntest('throws if transmit object does not have send function', ({ end, throws }) => {\n  throws(() => {\n    pino({ browser: { transmit: {} } })\n  })\n\n  throws(() => {\n    pino({ browser: { transmit: { send: 'not a func' } } })\n  })\n\n  end()\n})\n\ntest('calls send function after write', ({ end, is }) => {\n  let c = 0\n  const logger = pino({\n    browser: {\n      write: () => {\n        c++\n      },\n      transmit: {\n        send () { is(c, 1) }\n      }\n    }\n  })\n\n  logger.fatal({ test: 'test' })\n  end()\n})\n\ntest('passes send function the logged level', ({ end, is }) => {\n  const logger = pino({\n    browser: {\n      write () {},\n      transmit: {\n        send (level) {\n          is(level, 'fatal')\n        }\n      }\n    }\n  })\n\n  logger.fatal({ test: 'test' })\n  end()\n})\n\ntest('passes send function message strings in logEvent object when asObject is not set', ({ end, same, is }) => {\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, { messages }) {\n          is(messages[0], 'test')\n          is(messages[1], 'another test')\n        }\n      }\n    }\n  })\n\n  logger.fatal('test', 'another test')\n\n  end()\n})\n\ntest('passes send function message objects in logEvent object when asObject is not set', ({ end, same, is }) => {\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, { messages }) {\n          same(messages[0], { test: 'test' })\n          is(messages[1], 'another test')\n        }\n      }\n    }\n  })\n\n  logger.fatal({ test: 'test' }, 'another test')\n\n  end()\n})\n\ntest('passes send function message strings in logEvent object when asObject is set', ({ end, same, is }) => {\n  const logger = pino({\n    browser: {\n      asObject: true,\n      write: noop,\n      transmit: {\n        send (level, { messages }) {\n          is(messages[0], 'test')\n          is(messages[1], 'another test')\n        }\n      }\n    }\n  })\n\n  logger.fatal('test', 'another test')\n\n  end()\n})\n\ntest('passes send function message objects in logEvent object when asObject is set', ({ end, same, is }) => {\n  const logger = pino({\n    browser: {\n      asObject: true,\n      write: noop,\n      transmit: {\n        send (level, { messages }) {\n          same(messages[0], { test: 'test' })\n          is(messages[1], 'another test')\n        }\n      }\n    }\n  })\n\n  logger.fatal({ test: 'test' }, 'another test')\n\n  end()\n})\n\ntest('supplies a timestamp (ts) in logEvent object which is exactly the same as the `time` property in asObject mode', ({ end, is }) => {\n  let expected\n  const logger = pino({\n    browser: {\n      asObject: true, // implicit because `write`, but just to be explicit\n      write (o) {\n        expected = o.time\n      },\n      transmit: {\n        send (level, logEvent) {\n          is(logEvent.ts, expected)\n        }\n      }\n    }\n  })\n\n  logger.fatal('test')\n  end()\n})\n\ntest('passes send function child bindings via logEvent object', ({ end, same, is }) => {\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, logEvent) {\n          const messages = logEvent.messages\n          const bindings = logEvent.bindings\n          same(bindings[0], { first: 'binding' })\n          same(bindings[1], { second: 'binding2' })\n          same(messages[0], { test: 'test' })\n          is(messages[1], 'another test')\n        }\n      }\n    }\n  })\n\n  logger\n    .child({ first: 'binding' })\n    .child({ second: 'binding2' })\n    .fatal({ test: 'test' }, 'another test')\n  end()\n})\n\ntest('passes send function level:{label, value} via logEvent object', ({ end, is }) => {\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, logEvent) {\n          const label = logEvent.level.label\n          const value = logEvent.level.value\n\n          is(label, 'fatal')\n          is(value, 60)\n        }\n      }\n    }\n  })\n\n  logger.fatal({ test: 'test' }, 'another test')\n  end()\n})\n\ntest('calls send function according to transmit.level', ({ end, is }) => {\n  let c = 0\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        level: 'error',\n        send (level) {\n          c++\n          if (c === 1) is(level, 'error')\n          if (c === 2) is(level, 'fatal')\n        }\n      }\n    }\n  })\n  logger.warn('ignored')\n  logger.error('test')\n  logger.fatal('test')\n  end()\n})\n\ntest('transmit.level defaults to logger level', ({ end, is }) => {\n  let c = 0\n  const logger = pino({\n    level: 'error',\n    browser: {\n      write: noop,\n      transmit: {\n        send (level) {\n          c++\n          if (c === 1) is(level, 'error')\n          if (c === 2) is(level, 'fatal')\n        }\n      }\n    }\n  })\n  logger.warn('ignored')\n  logger.error('test')\n  logger.fatal('test')\n  end()\n})\n\ntest('transmit.level is effective even if lower than logger level', ({ end, is }) => {\n  let c = 0\n  const logger = pino({\n    level: 'error',\n    browser: {\n      write: noop,\n      transmit: {\n        level: 'info',\n        send (level) {\n          c++\n          if (c === 1) is(level, 'warn')\n          if (c === 2) is(level, 'error')\n          if (c === 3) is(level, 'fatal')\n        }\n      }\n    }\n  })\n  logger.warn('ignored')\n  logger.error('test')\n  logger.fatal('test')\n  end()\n})\n\ntest('applies all serializers to messages and bindings (serialize:false - default)', ({ end, same, is }) => {\n  const logger = pino({\n    serializers: {\n      first: () => 'first',\n      second: () => 'second',\n      test: () => 'serialize it'\n    },\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, logEvent) {\n          const messages = logEvent.messages\n          const bindings = logEvent.bindings\n          same(bindings[0], { first: 'first' })\n          same(bindings[1], { second: 'second' })\n          same(messages[0], { test: 'serialize it' })\n          is(messages[1].type, 'Error')\n        }\n      }\n    }\n  })\n\n  logger\n    .child({ first: 'binding' })\n    .child({ second: 'binding2' })\n    .fatal({ test: 'test' }, Error())\n  end()\n})\n\ntest('applies all serializers to messages and bindings (serialize:true)', ({ end, same, is }) => {\n  const logger = pino({\n    serializers: {\n      first: () => 'first',\n      second: () => 'second',\n      test: () => 'serialize it'\n    },\n    browser: {\n      serialize: true,\n      write: noop,\n      transmit: {\n        send (level, logEvent) {\n          const messages = logEvent.messages\n          const bindings = logEvent.bindings\n          same(bindings[0], { first: 'first' })\n          same(bindings[1], { second: 'second' })\n          same(messages[0], { test: 'serialize it' })\n          is(messages[1].type, 'Error')\n        }\n      }\n    }\n  })\n\n  logger\n    .child({ first: 'binding' })\n    .child({ second: 'binding2' })\n    .fatal({ test: 'test' }, Error())\n  end()\n})\n\ntest('extracts correct bindings and raw messages over multiple transmits', ({ end, same, is }) => {\n  let messages = null\n  let bindings = null\n\n  const logger = pino({\n    browser: {\n      write: noop,\n      transmit: {\n        send (level, logEvent) {\n          messages = logEvent.messages\n          bindings = logEvent.bindings\n        }\n      }\n    }\n  })\n\n  const child = logger.child({ child: true })\n  const grandchild = child.child({ grandchild: true })\n\n  logger.fatal({ test: 'parent:test1' })\n  logger.fatal({ test: 'parent:test2' })\n  same([], bindings)\n  same([{ test: 'parent:test2' }], messages)\n\n  child.fatal({ test: 'child:test1' })\n  child.fatal({ test: 'child:test2' })\n  same([{ child: true }], bindings)\n  same([{ test: 'child:test2' }], messages)\n\n  grandchild.fatal({ test: 'grandchild:test1' })\n  grandchild.fatal({ test: 'grandchild:test2' })\n  same([{ child: true }, { grandchild: true }], bindings)\n  same([{ test: 'grandchild:test2' }], messages)\n\n  end()\n})\n\ntest('does not log below configured level', ({ end, is }) => {\n  let message = null\n  const logger = pino({\n    level: 'info',\n    browser: {\n      write (o) {\n        message = o.msg\n      },\n      transmit: {\n        send () { }\n      }\n    }\n  })\n\n  logger.debug('this message is silent')\n  is(message, null)\n\n  end()\n})\n\ntest('silent level prevents logging even with transmit', ({ end, fail }) => {\n  const logger = pino({\n    level: 'silent',\n    browser: {\n      write () {\n        fail('no data should be logged by the write method')\n      },\n      transmit: {\n        send () {\n          fail('no data should be logged by the send method')\n        }\n      }\n    }\n  })\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    logger[level]('ignored')\n  })\n\n  end()\n})\n\ntest('does not call send when transmit.level is set to silent', ({ end, fail, is }) => {\n  let c = 0\n  const logger = pino({\n    level: 'trace',\n    browser: {\n      write () {\n        c++\n      },\n      transmit: {\n        level: 'silent',\n        send () {\n          fail('no data should be logged by the transmit method')\n        }\n      }\n    }\n  })\n\n  const levels = Object.keys(pino.levels.values)\n  levels.forEach((level) => {\n    logger[level]('message')\n  })\n\n  is(c, levels.length, 'write must be called exactly once per level')\n  end()\n})\n"
  },
  {
    "path": "test/browser.test.js",
    "content": "'use strict'\nconst test = require('tape')\nconst fresh = require('import-fresh')\nconst pinoStdSerializers = require('pino-std-serializers')\nconst pino = require('../browser')\n\nlevelTest('fatal')\nlevelTest('error')\nlevelTest('warn')\nlevelTest('info')\nlevelTest('debug')\nlevelTest('trace')\n\ntest('silent level', ({ end, fail, pass }) => {\n  const instance = pino({\n    level: 'silent',\n    browser: { write: fail }\n  })\n  instance.info('test')\n  const child = instance.child({ test: 'test' })\n  child.info('msg-test')\n  // use setTimeout because setImmediate isn't supported in most browsers\n  setTimeout(() => {\n    pass()\n    end()\n  }, 0)\n})\n\ntest('enabled false', ({ end, fail, pass }) => {\n  const instance = pino({\n    enabled: false,\n    browser: { write: fail }\n  })\n  instance.info('test')\n  const child = instance.child({ test: 'test' })\n  child.info('msg-test')\n  // use setTimeout because setImmediate isn't supported in most browsers\n  setTimeout(() => {\n    pass()\n    end()\n  }, 0)\n})\n\ntest('throw if creating child without bindings', ({ end, throws }) => {\n  const instance = pino()\n  throws(() => instance.child())\n  end()\n})\n\ntest('stubs write, flush and ee methods on instance', ({ end, ok, is }) => {\n  const instance = pino()\n\n  ok(isFunc(instance.setMaxListeners))\n  ok(isFunc(instance.getMaxListeners))\n  ok(isFunc(instance.emit))\n  ok(isFunc(instance.addListener))\n  ok(isFunc(instance.on))\n  ok(isFunc(instance.prependListener))\n  ok(isFunc(instance.once))\n  ok(isFunc(instance.prependOnceListener))\n  ok(isFunc(instance.removeListener))\n  ok(isFunc(instance.removeAllListeners))\n  ok(isFunc(instance.listeners))\n  ok(isFunc(instance.listenerCount))\n  ok(isFunc(instance.eventNames))\n  ok(isFunc(instance.write))\n  ok(isFunc(instance.flush))\n\n  is(instance.on(), undefined)\n\n  end()\n})\n\ntest('exposes levels object', ({ end, same }) => {\n  same(pino.levels, {\n    values: {\n      fatal: 60,\n      error: 50,\n      warn: 40,\n      info: 30,\n      debug: 20,\n      trace: 10\n    },\n    labels: {\n      10: 'trace',\n      20: 'debug',\n      30: 'info',\n      40: 'warn',\n      50: 'error',\n      60: 'fatal'\n    }\n  })\n\n  end()\n})\n\ntest('exposes faux stdSerializers', ({ end, ok, same }) => {\n  ok(pino.stdSerializers)\n  // make sure faux stdSerializers match pino-std-serializers\n  for (const serializer in pinoStdSerializers) {\n    ok(pino.stdSerializers[serializer], `pino.stdSerializers.${serializer}`)\n  }\n  // confirm faux methods return empty objects\n  same(pino.stdSerializers.req(), {})\n  same(pino.stdSerializers.mapHttpRequest(), {})\n  same(pino.stdSerializers.mapHttpResponse(), {})\n  same(pino.stdSerializers.res(), {})\n  // confirm wrapping function is a passthrough\n  const noChange = { foo: 'bar', fuz: 42 }\n  same(pino.stdSerializers.wrapRequestSerializer(noChange), noChange)\n  same(pino.stdSerializers.wrapResponseSerializer(noChange), noChange)\n  end()\n})\n\ntest('exposes err stdSerializer', ({ end, ok }) => {\n  ok(pino.stdSerializers.err)\n  ok(pino.stdSerializers.err(Error()))\n  end()\n})\n\nconsoleMethodTest('error')\nconsoleMethodTest('fatal', 'error')\nconsoleMethodTest('warn')\nconsoleMethodTest('info')\nconsoleMethodTest('debug')\nconsoleMethodTest('trace')\nabsentConsoleMethodTest('error', 'log')\nabsentConsoleMethodTest('warn', 'error')\nabsentConsoleMethodTest('info', 'log')\nabsentConsoleMethodTest('debug', 'log')\nabsentConsoleMethodTest('trace', 'log')\n\n// do not run this with airtap\nif (process.title !== 'browser') {\n  test('in absence of console, log methods become noops', ({ end, ok }) => {\n    const console = global.console\n    delete global.console\n    const instance = fresh('../browser')()\n    global.console = console\n    ok(fnName(instance.log).match(/noop/))\n    ok(fnName(instance.fatal).match(/noop/))\n    ok(fnName(instance.error).match(/noop/))\n    ok(fnName(instance.warn).match(/noop/))\n    ok(fnName(instance.info).match(/noop/))\n    ok(fnName(instance.debug).match(/noop/))\n    ok(fnName(instance.trace).match(/noop/))\n    end()\n  })\n}\n\ntest('opts.browser.asObject logs pino-like object to console', ({ end, ok, is }) => {\n  const info = console.info\n  console.info = function (o) {\n    is(o.level, 30)\n    is(o.msg, 'test')\n    ok(o.time)\n    console.info = info\n  }\n  const instance = require('../browser')({\n    browser: {\n      asObject: true\n    }\n  })\n\n  instance.info('test')\n  end()\n})\n\ntest('opts.browser.asObject uses opts.messageKey in logs', ({ end, ok, is }) => {\n  const messageKey = 'message'\n  const instance = require('../browser')({\n    messageKey,\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.level, 30)\n        is(o[messageKey], 'test')\n        ok(o.time)\n      }\n    }\n  })\n\n  instance.info('test')\n  end()\n})\n\ntest('opts.browser.asObjectBindingsOnly passes the bindings but keep the message unformatted', ({ end, ok, is, deepEqual }) => {\n  const messageKey = 'message'\n  const instance = require('../browser')({\n    messageKey,\n    browser: {\n      asObjectBindingsOnly: true,\n      write: function (o, msg, ...args) {\n        is(o.level, 30)\n        ok(o.time)\n        is(msg, 'test %s')\n        deepEqual(args, ['foo'])\n      }\n    }\n  })\n\n  instance.info('test %s', 'foo')\n  end()\n})\n\ntest('opts.browser.formatters (level) logs pino-like object to console', ({ end, ok, is }) => {\n  const info = console.info\n  console.info = function (o) {\n    is(o.level, 30)\n    is(o.label, 'info')\n    is(o.msg, 'test')\n    ok(o.time)\n    console.info = info\n  }\n  const instance = require('../browser')({\n    browser: {\n      formatters: {\n        level (label, number) {\n          return { label, level: number }\n        }\n      }\n    }\n  })\n\n  instance.info('test')\n  end()\n})\n\ntest('opts.browser.formatters (log) logs pino-like object to console', ({ end, ok, is }) => {\n  const info = console.info\n  console.info = function (o) {\n    is(o.level, 30)\n    is(o.msg, 'test')\n    is(o.hello, 'world')\n    is(o.newField, 'test')\n    ok(o.time, `Logged at ${o.time}`)\n    console.info = info\n  }\n  const instance = require('../browser')({\n    browser: {\n      formatters: {\n        log (o) {\n          return { ...o, newField: 'test', time: `Logged at ${o.time}` }\n        }\n      }\n    }\n  })\n\n  instance.info({ hello: 'world' }, 'test')\n  end()\n})\n\ntest('opts.browser.reportCaller adds caller in asObject mode', ({ end, ok }) => {\n  const instance = require('../browser')({\n    browser: {\n      asObject: true,\n      reportCaller: true,\n      write: function (o) {\n        ok(typeof o.caller === 'string' && o.caller.length > 0, 'has caller string')\n        ok(/:\\\\d+:\\\\d+/.test(o.caller) || /:\\d+:\\d+/.test(o.caller), `caller has line:col pattern: ${o.caller}`)\n      }\n    }\n  })\n\n  instance.info('test')\n  end()\n})\n\n// NOTE: Default (non-object) mode caller string is covered in docs\n// and manually verified. Keeping the test minimal to avoid cross-env flakiness.\n\ntest('opts.browser.serialize and opts.browser.transmit only serializes log data once', ({ end, ok, is }) => {\n  const instance = require('../browser')({\n    serializers: {\n      extras (data) {\n        return { serializedExtras: data }\n      }\n    },\n    browser: {\n      serialize: ['extras'],\n      transmit: {\n        level: 'info',\n        send (level, o) {\n          is(o.messages[0].extras.serializedExtras, 'world')\n        }\n      }\n    }\n  })\n\n  instance.info({ extras: 'world' }, 'test')\n  end()\n})\n\ntest('opts.browser.serialize and opts.asObject only serializes log data once', ({ end, ok, is }) => {\n  const instance = require('../browser')({\n    serializers: {\n      extras (data) {\n        return { serializedExtras: data }\n      }\n    },\n    browser: {\n      serialize: ['extras'],\n      asObject: true,\n      write: function (o) {\n        is(o.extras.serializedExtras, 'world')\n      }\n    }\n  })\n\n  instance.info({ extras: 'world' }, 'test')\n  end()\n})\n\ntest('opts.browser.serialize, opts.asObject and opts.browser.transmit only serializes log data once', ({ end, ok, is }) => {\n  const instance = require('../browser')({\n    serializers: {\n      extras (data) {\n        return { serializedExtras: data }\n      }\n    },\n    browser: {\n      serialize: ['extras'],\n      asObject: true,\n      transmit: {\n        send (level, o) {\n          is(o.messages[0].extras.serializedExtras, 'world')\n        }\n      }\n    }\n  })\n\n  instance.info({ extras: 'world' }, 'test')\n  end()\n})\n\ntest('opts.browser.write func log single string', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('test')\n\n  end()\n})\n\ntest('opts.browser.write func string joining', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test test2 test3')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('test %s %s', 'test2', 'test3')\n\n  end()\n})\n\ntest('opts.browser.write func string joining when asObject is true', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test test2 test3')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('test %s %s', 'test2', 'test3')\n\n  end()\n})\n\ntest('opts.browser.write func string object joining', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test {\"test\":\"test2\"} {\"test\":\"test3\"}')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('test %j %j', { test: 'test2' }, { test: 'test3' })\n\n  end()\n})\n\ntest('opts.browser.write func string object joining when asObject is true', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      asObject: true,\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test {\"test\":\"test2\"} {\"test\":\"test3\"}')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('test %j %j', { test: 'test2' }, { test: 'test3' })\n\n  end()\n})\n\ntest('opts.browser.write func string interpolation', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 'test2 test ({\"test\":\"test3\"})')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info('%s test (%j)', 'test2', { test: 'test3' })\n\n  end()\n})\n\ntest('opts.browser.write func number', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.msg, 1)\n        ok(o.time)\n      }\n    }\n  })\n  instance.info(1)\n\n  end()\n})\n\ntest('opts.browser.write func log single object', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: function (o) {\n        is(o.level, 30)\n        is(o.test, 'test')\n        ok(o.time)\n      }\n    }\n  })\n  instance.info({ test: 'test' })\n\n  end()\n})\n\ntest('opts.browser.write obj writes to methods corresponding to level', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write: {\n        error: function (o) {\n          is(o.level, 50)\n          is(o.test, 'test')\n          ok(o.time)\n        }\n      }\n    }\n  })\n  instance.error({ test: 'test' })\n\n  end()\n})\n\ntest('opts.browser.asObject/write supports child loggers', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write (o) {\n        is(o.level, 30)\n        is(o.test, 'test')\n        is(o.msg, 'msg-test')\n        ok(o.time)\n      }\n    }\n  })\n  const child = instance.child({ test: 'test' })\n  child.info('msg-test')\n\n  end()\n})\n\ntest('opts.browser.asObject/write supports child child loggers', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write (o) {\n        is(o.level, 30)\n        is(o.test, 'test')\n        is(o.foo, 'bar')\n        is(o.msg, 'msg-test')\n        ok(o.time)\n      }\n    }\n  })\n  const child = instance.child({ test: 'test' }).child({ foo: 'bar' })\n  child.info('msg-test')\n\n  end()\n})\n\ntest('opts.browser.asObject/write supports child child child loggers', ({ end, ok, is }) => {\n  const instance = pino({\n    browser: {\n      write (o) {\n        is(o.level, 30)\n        is(o.test, 'test')\n        is(o.foo, 'bar')\n        is(o.baz, 'bop')\n        is(o.msg, 'msg-test')\n        ok(o.time)\n      }\n    }\n  })\n  const child = instance.child({ test: 'test' }).child({ foo: 'bar' }).child({ baz: 'bop' })\n  child.info('msg-test')\n\n  end()\n})\n\ntest('opts.browser.asObject defensively mitigates naughty numbers', ({ end, pass }) => {\n  const instance = pino({\n    browser: { asObject: true, write: () => {} }\n  })\n  const child = instance.child({ test: 'test' })\n  child._childLevel = -10\n  child.info('test')\n  pass() // if we reached here, there was no infinite loop, so, .. pass.\n\n  end()\n})\n\ntest('opts.browser.write obj falls back to console where a method is not supplied', ({ end, ok, is }) => {\n  const info = console.info\n  console.info = (o) => {\n    is(o.level, 30)\n    is(o.msg, 'test')\n    ok(o.time)\n    console.info = info\n  }\n  const instance = require('../browser')({\n    browser: {\n      write: {\n        error (o) {\n          is(o.level, 50)\n          is(o.test, 'test')\n          ok(o.time)\n        }\n      }\n    }\n  })\n  instance.error({ test: 'test' })\n  instance.info('test')\n\n  end()\n})\n\nfunction levelTest (name) {\n  test(name + ' logs', ({ end, is }) => {\n    const msg = 'hello world'\n    sink(name, (args) => {\n      is(args[0], msg)\n      end()\n    })\n    pino({ level: name })[name](msg)\n  })\n\n  test('passing objects at level ' + name, ({ end, is }) => {\n    const msg = { hello: 'world' }\n    sink(name, (args) => {\n      is(args[0], msg)\n      end()\n    })\n    pino({ level: name })[name](msg)\n  })\n\n  test('passing an object and a string at level ' + name, ({ end, is }) => {\n    const a = { hello: 'world' }\n    const b = 'a string'\n    sink(name, (args) => {\n      is(args[0], a)\n      is(args[1], b)\n      end()\n    })\n    pino({ level: name })[name](a, b)\n  })\n\n  test('formatting logs as ' + name, ({ end, is }) => {\n    sink(name, (args) => {\n      is(args[0], 'hello %d')\n      is(args[1], 42)\n      end()\n    })\n    pino({ level: name })[name]('hello %d', 42)\n  })\n\n  test('passing error at level ' + name, ({ end, is }) => {\n    const err = new Error('myerror')\n    sink(name, (args) => {\n      is(args[0], err)\n      end()\n    })\n    pino({ level: name })[name](err)\n  })\n\n  test('passing error with a serializer at level ' + name, ({ end, is }) => {\n    // in browser - should have no effect (should not crash)\n    const err = new Error('myerror')\n    sink(name, (args) => {\n      is(args[0].err, err)\n      end()\n    })\n    const instance = pino({\n      level: name,\n      serializers: {\n        err: pino.stdSerializers.err\n      }\n    })\n    instance[name]({ err })\n  })\n\n  test('child logger for level ' + name, ({ end, is }) => {\n    const msg = 'hello world'\n    const parent = { hello: 'world' }\n    sink(name, (args) => {\n      is(args[0], parent)\n      is(args[1], msg)\n      end()\n    })\n    const instance = pino({ level: name })\n    const child = instance.child(parent)\n    child[name](msg)\n  })\n\n  test('child-child logger for level ' + name, ({ end, is }) => {\n    const msg = 'hello world'\n    const grandParent = { hello: 'world' }\n    const parent = { hello: 'you' }\n    sink(name, (args) => {\n      is(args[0], grandParent)\n      is(args[1], parent)\n      is(args[2], msg)\n      end()\n    })\n    const instance = pino({ level: name })\n    const child = instance.child(grandParent).child(parent)\n    child[name](msg)\n  })\n}\n\nfunction consoleMethodTest (level, method) {\n  if (!method) method = level\n  test('pino().' + level + ' uses console.' + method, ({ end, is }) => {\n    sink(method, (args) => {\n      is(args[0], 'test')\n      end()\n    })\n    const instance = require('../browser')({ level })\n    instance[level]('test')\n  })\n}\n\nfunction absentConsoleMethodTest (method, fallback) {\n  test('in absence of console.' + method + ', console.' + fallback + ' is used', ({ end, is }) => {\n    const fn = console[method]\n    console[method] = undefined\n    sink(fallback, function (args) {\n      is(args[0], 'test')\n      end()\n      console[method] = fn\n    })\n    const instance = require('../browser')({ level: method })\n    instance[method]('test')\n  })\n}\n\nfunction isFunc (fn) { return typeof fn === 'function' }\nfunction fnName (fn) {\n  const rx = /^\\s*function\\s*([^(]*)/i\n  const match = rx.exec(fn)\n  return match && match[1]\n}\nfunction sink (method, fn) {\n  if (method === 'fatal') method = 'error'\n  const orig = console[method]\n  console[method] = function () {\n    console[method] = orig\n    fn(Array.prototype.slice.call(arguments))\n  }\n}\n"
  },
  {
    "path": "test/complex-objects.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { PassThrough } = require('node:stream')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\ntest('Proxy and stream objects', async () => {\n  const s = new PassThrough()\n  s.resume()\n  s.write('', () => {})\n  const obj = { s, p: new Proxy({}, { get () { throw new Error('kaboom') } }) }\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info({ obj })\n\n  const result = await once(stream, 'data')\n\n  assert.equal(result.obj, '[unable to serialize, circular reference is too complex to analyze]')\n})\n\ntest('Proxy and stream objects', async () => {\n  const s = new PassThrough()\n  s.resume()\n  s.write('', () => {})\n  const obj = { s, p: new Proxy({}, { get () { throw new Error('kaboom') } }) }\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info(obj)\n\n  const result = await once(stream, 'data')\n\n  assert.equal(result.p, '[unable to serialize, circular reference is too complex to analyze]')\n})\n"
  },
  {
    "path": "test/crlf.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst writer = require('flush-write-stream')\nconst pino = require('../')\n\nfunction capture () {\n  const ws = writer((chunk, enc, cb) => {\n    ws.data += chunk.toString()\n    cb()\n  })\n  ws.data = ''\n  return ws\n}\n\ntest('pino uses LF by default', async () => {\n  const stream = capture()\n  const logger = pino(stream)\n  logger.info('foo')\n  logger.error('bar')\n  assert.ok(/foo[^\\r\\n]+\\n[^\\r\\n]+bar[^\\r\\n]+\\n/.test(stream.data))\n})\n\ntest('pino can log CRLF', async () => {\n  const stream = capture()\n  const logger = pino({\n    crlf: true\n  }, stream)\n  logger.info('foo')\n  logger.error('bar')\n  assert.ok(/foo[^\\n]+\\r\\n[^\\n]+bar[^\\n]+\\r\\n/.test(stream.data))\n})\n"
  },
  {
    "path": "test/custom-levels.test.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\n// Silence all warnings for this test\nprocess.removeAllListeners('warning')\nprocess.on('warning', () => {})\n\ntest('adds additional levels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35,\n      bar: 45\n    }\n  }, stream)\n\n  logger.foo('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 35)\n})\n\ntest('custom levels does not override default levels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35\n    }\n  }, stream)\n\n  logger.info('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 30)\n})\n\ntest('default levels can be redefined using custom levels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      info: 35,\n      debug: 45\n    },\n    useOnlyCustomLevels: true\n  }, stream)\n\n  assert.equal(logger.hasOwnProperty('info'), true)\n\n  logger.info('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 35)\n})\n\ntest('custom levels overrides default level label if use useOnlyCustomLevels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35\n    },\n    useOnlyCustomLevels: true,\n    level: 'foo'\n  }, stream)\n\n  assert.equal(logger.hasOwnProperty('info'), false)\n})\n\ntest('custom levels overrides default level value if use useOnlyCustomLevels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35\n    },\n    useOnlyCustomLevels: true,\n    level: 35\n  }, stream)\n\n  assert.equal(logger.hasOwnProperty('info'), false)\n})\n\ntest('custom levels are inherited by children', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35\n    }\n  }, stream)\n\n  logger.child({ childMsg: 'ok' }).foo('test')\n  const { msg, childMsg, level } = await once(stream, 'data')\n  assert.equal(level, 35)\n  assert.equal(childMsg, 'ok')\n  assert.equal(msg, 'test')\n})\n\ntest('custom levels can be specified on child bindings', async () => {\n  const stream = sink()\n  const logger = pino(stream).child({\n    childMsg: 'ok'\n  }, {\n    customLevels: {\n      foo: 35\n    }\n  })\n\n  logger.foo('test')\n  const { msg, childMsg, level } = await once(stream, 'data')\n  assert.equal(level, 35)\n  assert.equal(childMsg, 'ok')\n  assert.equal(msg, 'test')\n})\n\ntest('customLevels property child bindings does not get logged', async () => {\n  const stream = sink()\n  const logger = pino(stream).child({\n    childMsg: 'ok'\n  }, {\n    customLevels: {\n      foo: 35\n    }\n  })\n\n  logger.foo('test')\n  const { customLevels } = await once(stream, 'data')\n  assert.equal(customLevels, undefined)\n})\n\ntest('throws when specifying pre-existing parent labels via child bindings', async () => {\n  const stream = sink()\n  assert.throws(\n    () => pino({\n      customLevels: {\n        foo: 35\n      }\n    }, stream).child({}, {\n      customLevels: {\n        foo: 45\n      }\n    }),\n    /levels cannot be overridden/\n  )\n})\n\ntest('throws when specifying pre-existing parent values via child bindings', async () => {\n  const stream = sink()\n  assert.throws(\n    () => pino({\n      customLevels: {\n        foo: 35\n      }\n    }, stream).child({}, {\n      customLevels: {\n        bar: 35\n      }\n    }),\n    /pre-existing level values cannot be used for new levels/\n  )\n})\n\ntest('throws when specifying core values via child bindings', async () => {\n  const stream = sink()\n  assert.throws(\n    () => pino(stream).child({}, {\n      customLevels: {\n        foo: 30\n      }\n    }),\n    /pre-existing level values cannot be used for new levels/\n  )\n})\n\ntest('throws when useOnlyCustomLevels is set true without customLevels', async () => {\n  const stream = sink()\n  assert.throws(\n    () => pino({\n      useOnlyCustomLevels: true\n    }, stream),\n    /customLevels is required if useOnlyCustomLevels is set true/\n  )\n})\n\ntest('custom level on one instance does not affect other instances', async () => {\n  pino({\n    customLevels: {\n      foo: 37\n    }\n  })\n  assert.equal(typeof pino().foo, 'undefined')\n})\n\ntest('setting level below or at custom level will successfully log', async () => {\n  const stream = sink()\n  const instance = pino({ customLevels: { foo: 35 } }, stream)\n  instance.level = 'foo'\n  instance.info('nope')\n  instance.foo('bar')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'bar')\n})\n\ntest('custom level below level threshold will not log', async () => {\n  const stream = sink()\n  const instance = pino({ customLevels: { foo: 15 } }, stream)\n  instance.level = 'info'\n  instance.info('bar')\n  instance.foo('nope')\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, 'bar')\n})\n\ntest('does not share custom level state across siblings', async () => {\n  const stream = sink()\n  const logger = pino(stream)\n  logger.child({}, {\n    customLevels: { foo: 35 }\n  })\n  assert.doesNotThrow(() => {\n    logger.child({}, {\n      customLevels: { foo: 35 }\n    })\n  })\n})\n\ntest('custom level does not affect the levels serializer', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      foo: 35,\n      bar: 45\n    },\n    formatters: {\n      level (label, number) {\n        return { priority: number }\n      }\n    }\n  }, stream)\n\n  logger.foo('test')\n  const { priority } = await once(stream, 'data')\n  assert.equal(priority, 35)\n})\n\ntest('When useOnlyCustomLevels is set to true, the level formatter should only get custom levels', async () => {\n  const stream = sink()\n  const logger = pino({\n    customLevels: {\n      answer: 42\n    },\n    useOnlyCustomLevels: true,\n    level: 42,\n    formatters: {\n      level (label, number) {\n        assert.equal(label, 'answer')\n        assert.equal(number, 42)\n        return { level: number }\n      }\n    }\n  }, stream)\n\n  logger.answer('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 42)\n})\n"
  },
  {
    "path": "test/diagnostics.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst os = require('node:os')\nconst diagChan = require('node:diagnostics_channel')\nconst { AsyncLocalStorage } = require('node:async_hooks')\nconst { Writable } = require('node:stream')\nconst tspl = require('@matteo.collina/tspl')\nconst pino = require('../pino')\n\nconst hostname = os.hostname()\nconst { pid } = process\nconst AS_JSON_START = 'tracing:pino_asJson:start'\nconst AS_JSON_END = 'tracing:pino_asJson:end'\n\n// Skip tests if diagnostics_channel.tracingChannel is not available (Node < 18.19)\nconst skip = typeof diagChan.tracingChannel !== 'function'\n\ntest.beforeEach(ctx => {\n  ctx.pino = {\n    ts: 1757512800000, // 2025-09-10T10:00:00.000-05:00\n    now: Date.now\n  }\n\n  Date.now = () => ctx.pino.ts\n\n  ctx.pino.dest = new Writable({\n    objectMode: true,\n    write (data, enc, cb) {\n      cb()\n    }\n  })\n})\n\ntest.afterEach(ctx => {\n  Date.now = ctx.pino.now\n})\n\ntest('asJson emits events', { skip }, async (t) => {\n  const plan = tspl(t, { plan: 8 })\n  const { dest } = t.pino\n  const logger = pino({}, dest)\n  const expectedArguments = [\n    {},\n    'testing',\n    30,\n    `,\"time\":${t.pino.ts}`\n  ]\n\n  let startEvent\n  diagChan.subscribe(AS_JSON_START, startHandler)\n  diagChan.subscribe(AS_JSON_END, endHandler)\n\n  logger.info('testing')\n  await plan\n\n  diagChan.unsubscribe(AS_JSON_START, startHandler)\n  diagChan.unsubscribe(AS_JSON_END, endHandler)\n\n  function startHandler (event) {\n    startEvent = event\n    plan.equal(Object.prototype.toString.call(event.instance), '[object Pino]')\n    plan.equal(event.instance === logger, true)\n    plan.deepStrictEqual(Array.from(event.arguments ?? []), expectedArguments)\n  }\n\n  function endHandler (event) {\n    plan.equal(Object.prototype.toString.call(event.instance), '[object Pino]')\n    plan.equal(event.instance === logger, true)\n    plan.deepStrictEqual(Array.from(event.arguments ?? []), expectedArguments)\n    plan.equal(\n      event.result,\n      `{\"level\":30,\"time\":${t.pino.ts},\"pid\":${pid},\"hostname\":\"${hostname}\",\"msg\":\"testing\"}\\n`\n    )\n\n    plan.equal(event.arguments === startEvent.arguments, true, 'same event object is supplied to both events')\n  }\n})\n\ntest('asJson context is not lost', { skip }, async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const { dest } = t.pino\n  const logger = pino({}, dest)\n  const asyncLocalStorage = new AsyncLocalStorage()\n  const localStore = { foo: 'bar' }\n\n  diagChan.subscribe(AS_JSON_START, startHandler)\n  diagChan.subscribe(AS_JSON_END, endHandler)\n\n  asyncLocalStorage.run(localStore, () => {\n    logger.info('testing')\n  })\n  await plan\n\n  diagChan.unsubscribe(AS_JSON_START, startHandler)\n  diagChan.unsubscribe(AS_JSON_END, endHandler)\n\n  function startHandler () {\n    const store = asyncLocalStorage.getStore()\n    plan.equal(store === localStore, true)\n  }\n\n  function endHandler () {\n    const store = asyncLocalStorage.getStore()\n    plan.equal(store === localStore, true)\n  }\n})\n"
  },
  {
    "path": "test/error-key.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\nconst stdSerializers = require('pino-std-serializers')\nconst pino = require('../')\n\ntest('set the errorKey with error serializer', async () => {\n  const stream = sink()\n  const errorKey = 'error'\n  const instance = pino({\n    errorKey,\n    serializers: { [errorKey]: stdSerializers.err }\n  }, stream)\n  instance.error(new ReferenceError('test'))\n  const o = await once(stream, 'data')\n  assert.equal(typeof o[errorKey], 'object')\n  assert.equal(o[errorKey].type, 'ReferenceError')\n  assert.equal(o[errorKey].message, 'test')\n  assert.equal(typeof o[errorKey].stack, 'string')\n})\n\ntest('set the errorKey without error serializer', async () => {\n  const stream = sink()\n  const errorKey = 'error'\n  const instance = pino({\n    errorKey\n  }, stream)\n  instance.error(new ReferenceError('test'))\n  const o = await once(stream, 'data')\n  assert.equal(typeof o[errorKey], 'object')\n  assert.equal(o[errorKey].type, 'ReferenceError')\n  assert.equal(o[errorKey].message, 'test')\n  assert.equal(typeof o[errorKey].stack, 'string')\n})\n"
  },
  {
    "path": "test/error.test.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst { pid } = process\nconst hostname = os.hostname()\nconst level = 50\nconst name = 'error'\n\ntest('err is serialized with additional properties set on the Error object', async () => {\n  const stream = sink()\n  const err = Object.assign(new Error('myerror'), { foo: 'bar' })\n  const instance = pino(stream)\n  instance.level = name\n  instance[name](err)\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack,\n      foo: err.foo\n    },\n    msg: err.message\n  })\n})\n\ntest('type should be detected based on constructor', async () => {\n  class Bar extends Error {}\n  const stream = sink()\n  const err = new Bar('myerror')\n  const instance = pino(stream)\n  instance.level = name\n  instance[name](err)\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    err: {\n      type: 'Bar',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('type, message and stack should be first level properties', async () => {\n  const stream = sink()\n  const err = Object.assign(new Error('foo'), { foo: 'bar' })\n  const instance = pino(stream)\n  instance.level = name\n  instance[name](err)\n\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack,\n      foo: err.foo\n    },\n    msg: err.message\n  })\n})\n\ntest('err serializer', async () => {\n  const stream = sink()\n  const err = Object.assign(new Error('myerror'), { foo: 'bar' })\n  const instance = pino({\n    serializers: {\n      err: pino.stdSerializers.err\n    }\n  }, stream)\n\n  instance.level = name\n  instance[name]({ err })\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack,\n      foo: err.foo\n    },\n    msg: err.message\n  })\n})\n\ntest('an error with statusCode property is not confused for a http response', async () => {\n  const stream = sink()\n  const err = Object.assign(new Error('StatusCodeErr'), { statusCode: 500 })\n  const instance = pino(stream)\n\n  instance.level = name\n  instance[name](err)\n  const result = await once(stream, 'data')\n\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack,\n      statusCode: err.statusCode\n    },\n    msg: err.message\n  })\n})\n\ntest('stack is omitted if it is not set on err', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const err = new Error('myerror')\n  delete err.stack\n  const instance = pino(sink(function (chunk, enc, cb) {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.equal(chunk.hasOwnProperty('stack'), false)\n    cb()\n  }))\n\n  instance.level = name\n  instance[name](err)\n\n  await plan\n})\n\ntest('correctly ignores toString on errors', async () => {\n  const err = new Error('myerror')\n  err.toString = () => undefined\n  const stream = sink()\n  const instance = pino({\n    test: 'this'\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('assign mixin()', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      return { hello: 'world' }\n    }\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    hello: 'world',\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('no err serializer', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    serializers: {}\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('empty serializer', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    serializers: {\n      err () {}\n    }\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    msg: err.message\n  })\n})\n\ntest('assign mixin()', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      return { hello: 'world' }\n    }\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    hello: 'world',\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('no err serializer', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    serializers: {}\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    err: {\n      type: 'Error',\n      message: err.message,\n      stack: err.stack\n    },\n    msg: err.message\n  })\n})\n\ntest('empty serializer', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({\n    serializers: {\n      err () {}\n    }\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    msg: err.message\n  })\n})\n\ntest('correctly adds error information when nestedKey is used', async () => {\n  const err = new Error('myerror')\n  err.toString = () => undefined\n  const stream = sink()\n  const instance = pino({\n    test: 'this',\n    nestedKey: 'obj'\n  }, stream)\n  instance.fatal(err)\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    obj: {\n      err: {\n        type: 'Error',\n        stack: err.stack,\n        message: err.message\n      }\n    },\n    msg: err.message\n  })\n})\n\ntest('correctly adds msg on error when nestedKey is used', async () => {\n  const err = new Error('myerror')\n  err.toString = () => undefined\n  const stream = sink()\n  const instance = pino({\n    test: 'this',\n    nestedKey: 'obj'\n  }, stream)\n  instance.fatal(err, 'msg message')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    obj: {\n      err: {\n        type: 'Error',\n        stack: err.stack,\n        message: err.message\n      }\n    },\n    msg: 'msg message'\n  })\n})\n\ntest('msg should take precedence over error message on mergingObject', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino(stream)\n  instance.error({ msg: 'my message', err })\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 50,\n    err: {\n      type: 'Error',\n      stack: err.stack,\n      message: err.message\n    },\n    msg: 'my message'\n  })\n})\n\ntest('considers messageKey when giving msg precedence over error', async () => {\n  const err = new Error('myerror')\n  const stream = sink()\n  const instance = pino({ messageKey: 'message' }, stream)\n  instance.error({ message: 'my message', err })\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 50,\n    err: {\n      type: 'Error',\n      stack: err.stack,\n      message: err.message\n    },\n    message: 'my message'\n  })\n})\n"
  },
  {
    "path": "test/escaping.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\nfunction testEscape (ch, key) {\n  test('correctly escape ' + ch, async () => {\n    const stream = sink()\n    const instance = pino({\n      name: 'hello'\n    }, stream)\n    instance.fatal('this contains ' + key)\n    const result = await once(stream, 'data')\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level: 60,\n      name: 'hello',\n      msg: 'this contains ' + key\n    })\n  })\n}\n\ntestEscape('\\\\n', '\\n')\ntestEscape('\\\\/', '/')\ntestEscape('\\\\\\\\', '\\\\')\ntestEscape('\\\\r', '\\r')\ntestEscape('\\\\t', '\\t')\ntestEscape('\\\\b', '\\b')\n\nconst toEscape = [\n  '\\u0000', // NUL  Null character\n  '\\u0001', // SOH  Start of Heading\n  '\\u0002', // STX  Start of Text\n  '\\u0003', // ETX  End-of-text character\n  '\\u0004', // EOT  End-of-transmission character\n  '\\u0005', // ENQ  Enquiry character\n  '\\u0006', // ACK  Acknowledge character\n  '\\u0007', // BEL  Bell character\n  '\\u0008', // BS   Backspace\n  '\\u0009', // HT   Horizontal tab\n  '\\u000A', // LF   Line feed\n  '\\u000B', // VT   Vertical tab\n  '\\u000C', // FF   Form feed\n  '\\u000D', // CR   Carriage return\n  '\\u000E', // SO   Shift Out\n  '\\u000F', // SI   Shift In\n  '\\u0010', // DLE  Data Link Escape\n  '\\u0011', // DC1  Device Control 1\n  '\\u0012', // DC2  Device Control 2\n  '\\u0013', // DC3  Device Control 3\n  '\\u0014', // DC4  Device Control 4\n  '\\u0015', // NAK  Negative-acknowledge character\n  '\\u0016', // SYN  Synchronous Idle\n  '\\u0017', // ETB  End of Transmission Block\n  '\\u0018', // CAN  Cancel character\n  '\\u0019', // EM   End of Medium\n  '\\u001A', // SUB  Substitute character\n  '\\u001B', // ESC  Escape character\n  '\\u001C', // FS   File Separator\n  '\\u001D', // GS   Group Separator\n  '\\u001E', // RS   Record Separator\n  '\\u001F' // US   Unit Separator\n]\n\ntoEscape.forEach((key) => {\n  testEscape(JSON.stringify(key), key)\n})\n\ntest('correctly escape `hello \\\\u001F world \\\\n \\\\u0022`', async () => {\n  const stream = sink()\n  const instance = pino({\n    name: 'hello'\n  }, stream)\n  instance.fatal('hello \\u001F world \\n \\u0022')\n  const result = await once(stream, 'data')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 60,\n    name: 'hello',\n    msg: 'hello \\u001F world \\n \\u0022'\n  })\n})\n"
  },
  {
    "path": "test/esm/esm.mjs",
    "content": "import test from 'node:test'\nimport assert from 'node:assert'\n\nimport pino from '../../pino.js'\nimport helper from '../helper.js'\n\nconst { sink, check, once } = helper\n\ntest('esm support', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info('hello world')\n  check(assert.equal, await once(stream, 'data'), 30, 'hello world')\n})\n"
  },
  {
    "path": "test/esm/index.test.js",
    "content": "'use strict'\n\n// Node v8 throw a `SyntaxError: Unexpected token import`\n// even if this branch is never touched in the code,\n// by using `eval` we can avoid this issue.\n// eslint-disable-next-line\n  new Function('module', 'return import(module)')('./esm.mjs').catch((err) => {\n  process.nextTick(() => {\n    throw err\n  })\n})\n\n// Node v8 throw a `SyntaxError: Unexpected token import`\n// even if this branch is never touched in the code,\n// by using `eval` we can avoid this issue.\n// eslint-disable-next-line\n  new Function('module', 'return import(module)')('./named-exports.mjs').catch((err) => {\n  process.nextTick(() => {\n    throw err\n  })\n})\n"
  },
  {
    "path": "test/esm/named-exports.mjs",
    "content": "import test from 'node:test'\nimport assert from 'node:assert'\nimport { hostname } from 'node:os'\nimport { readFileSync } from 'node:fs'\n\nimport { sink, check, once, watchFileCreated, file } from '../helper.js'\nimport { pino, destination } from '../../pino.js'\n\ntest('named exports support', async () => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info('hello world')\n  check(assert.equal, await once(stream, 'data'), 30, 'hello world')\n})\n\ntest('destination', async () => {\n  const tmp = file()\n  const instance = pino(destination(tmp))\n  instance.info('hello')\n  await watchFileCreated(tmp)\n  const result = JSON.parse(readFileSync(tmp).toString())\n  delete result.time\n  assert.deepEqual(result, {\n    pid: process.pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n"
  },
  {
    "path": "test/exit.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\n\nconst execa = require('execa')\nconst writer = require('flush-write-stream')\nconst { once } = require('./helper')\n\n// https://github.com/pinojs/pino/issues/542\ntest('pino.destination log everything when calling process.exit(0)', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'destination-exit.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n\n  await once(child, 'close')\n\n  assert.equal(actual.match(/hello/) != null, true)\n  assert.equal(actual.match(/world/) != null, true)\n})\n\ntest('pino with no args log everything when calling process.exit(0)', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'default-exit.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n\n  await once(child, 'close')\n\n  assert.equal(actual.match(/hello/) != null, true)\n  assert.equal(actual.match(/world/) != null, true)\n})\n\ntest('sync false logs everything when calling process.exit(0)', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'syncfalse-exit.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n\n  await once(child, 'close')\n\n  assert.equal(actual.match(/hello/) != null, true)\n  assert.equal(actual.match(/world/) != null, true)\n})\n\ntest('sync false logs everything when calling flushSync', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'syncfalse-flush-exit.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n\n  await once(child, 'close')\n\n  assert.equal(actual.match(/hello/) != null, true)\n  assert.equal(actual.match(/world/) != null, true)\n})\n\ntest('transports exits gracefully when logging in exit', async () => {\n  const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'transport-with-on-exit.js')])\n  child.stdout.resume()\n\n  const code = await once(child, 'close')\n\n  assert.equal(code, 0)\n})\n"
  },
  {
    "path": "test/fixtures/broken-pipe/basic.js",
    "content": "'use strict'\n\nglobal.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\n\nconst pino = require('../../..')()\n\npino.info('hello world')\n"
  },
  {
    "path": "test/fixtures/broken-pipe/destination.js",
    "content": "'use strict'\n\nglobal.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\n\nconst pino = require('../../..')\nconst logger = pino(pino.destination())\n\nlogger.info('hello world')\n"
  },
  {
    "path": "test/fixtures/broken-pipe/syncfalse.js",
    "content": "'use strict'\n\nglobal.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\n\nconst pino = require('../../..')\nconst logger = pino(pino.destination({ sync: false }))\n\nfor (var i = 0; i < 1000; i++) {\n  logger.info('hello world')\n}\n"
  },
  {
    "path": "test/fixtures/console-transport.js",
    "content": "const { Writable } = require('node:stream')\n\nmodule.exports = (options) => {\n  const myTransportStream = new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      // apply a transform and send to stdout\n      console.log(chunk.toString().toUpperCase())\n      cb()\n    }\n  })\n  return myTransportStream\n}\n"
  },
  {
    "path": "test/fixtures/crashing-transport.js",
    "content": "const { Writable } = require('node:stream')\n\nmodule.exports = () =>\n  new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      setImmediate(() => {\n        /* eslint-disable no-empty */\n        for (let i = 0; i < 1e3; i++) {}\n        process.exit(0)\n      })\n    }\n  })\n"
  },
  {
    "path": "test/fixtures/default-exit.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst logger = pino()\nlogger.info('hello')\nlogger.info('world')\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/destination-exit.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst logger = pino({}, pino.destination(1))\nlogger.info('hello')\nlogger.info('world')\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/eval/index.js",
    "content": "/* eslint-disable no-eval */\n\neval(`\nconst pino = require('../../../')\n\nconst logger = pino(\n  pino.transport({\n    target: 'pino/file'\n  })\n)\n\nlogger.info('done!')\n`)\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/14-files.js",
    "content": "const file1 = require(\"./file1.js\")\n\nfile1()\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/2-files.js",
    "content": "const file12 = require(\"./file12.js\")\n\nfile12()\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file1.js",
    "content": "const file2 = require(\"./file2.js\")\n\nmodule.exports = function () {\n    file2()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file10.js",
    "content": "const file11 = require(\"./file11.js\")\n\nmodule.exports = function () {\n    file11()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file11.js",
    "content": "const file12 = require(\"./file12.js\")\n\nmodule.exports = function () {\n    file12()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file12.js",
    "content": "const file13 = require(\"./file13.js\")\n\nmodule.exports = function () {\n    file13()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file13.js",
    "content": "const file14 = require(\"./file14.js\")\n\nmodule.exports = function () {\n    file14()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file14.js",
    "content": "const pino = require(\"../../../../\");\n\nmodule.exports = function() {\n    const logger = pino(\n        pino.transport({\n            target: 'pino/file'\n        })\n    )\n\n    logger.info('done!')\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file2.js",
    "content": "const file3 = require(\"./file3.js\")\n\nmodule.exports = function () {\n    file3()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file3.js",
    "content": "const file4 = require(\"./file4.js\")\n\nmodule.exports = function () {\n    file4()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file4.js",
    "content": "const file5 = require(\"./file5.js\")\n\nmodule.exports = function () {\n    file5()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file5.js",
    "content": "const file6 = require(\"./file6.js\")\n\nmodule.exports = function () {\n    file6()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file6.js",
    "content": "const file7 = require(\"./file7.js\")\n\nmodule.exports = function () {\n    file7()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file7.js",
    "content": "const file8 = require(\"./file8.js\")\n\nmodule.exports = function () {\n    file8()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file8.js",
    "content": "const file9 = require(\"./file9.js\")\n\nmodule.exports = function () {\n    file9()\n}\n"
  },
  {
    "path": "test/fixtures/eval/node_modules/file9.js",
    "content": "const file10 = require(\"./file10.js\")\n\nmodule.exports = function () {\n    file10()\n}\n"
  },
  {
    "path": "test/fixtures/noop-transport.js",
    "content": "const { Writable } = require('node:stream')\n\nmodule.exports = () => {\n  return new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      cb()\n    }\n  })\n}\n"
  },
  {
    "path": "test/fixtures/pretty/null-prototype.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../../'))\nconst log = pino({ prettyPrint: true })\nconst obj = Object.create(null)\nObject.assign(obj, { foo: 'bar' })\nlog.info(obj, 'hello')\n"
  },
  {
    "path": "test/fixtures/stdout-hack-protection.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\n\nconst write = process.stdout.write.bind(process.stdout)\nprocess.stdout.write = function (chunk) {\n  write('hack ' + chunk)\n}\n\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('../../'))()\npino.info('me')\n"
  },
  {
    "path": "test/fixtures/syncfalse-child.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst asyncLogger = pino(pino.destination({ sync: false })).child({ hello: 'world' })\nasyncLogger.info('h')\n"
  },
  {
    "path": "test/fixtures/syncfalse-exit.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst dest = pino.destination({ dest: 1, minLength: 4096, sync: false })\nconst logger = pino({}, dest)\nlogger.info('hello')\nlogger.info('world')\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/syncfalse-flush-exit.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst dest = pino.destination({ dest: 1, minLength: 4096, sync: false })\nconst logger = pino({}, dest)\nlogger.info('hello')\nlogger.info('world')\ndest.flushSync()\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/syncfalse.js",
    "content": "global.process = { __proto__: process, pid: 123456 }\nDate.now = function () { return 1459875739796 }\nrequire('node:os').hostname = function () { return 'abcdefghijklmnopqr' }\nconst pino = require(require.resolve('./../../'))\nconst asyncLogger = pino(pino.destination({ minLength: 4096, sync: false }))\nasyncLogger.info('h')\n"
  },
  {
    "path": "test/fixtures/syntax-error-esm.mjs",
    "content": "// This is a syntax error\nimport\n"
  },
  {
    "path": "test/fixtures/to-file-transport-with-transform.js",
    "content": "'use strict'\n\nconst fs = require('node:fs')\nconst { once } = require('node:events')\nconst { Transform } = require('node:stream')\n\nasync function run (opts) {\n  if (!opts.destination) throw new Error('kaboom')\n  const stream = fs.createWriteStream(opts.destination)\n  await once(stream, 'open')\n  const t = new Transform({\n    transform (chunk, enc, cb) {\n      setImmediate(cb, null, chunk.toString().toUpperCase())\n    }\n  })\n  t.pipe(stream)\n  return t\n}\n\nmodule.exports = run\n"
  },
  {
    "path": "test/fixtures/to-file-transport.js",
    "content": "'use strict'\n\nconst fs = require('node:fs')\nconst { once } = require('node:events')\n\nasync function run (opts) {\n  if (!opts.destination) throw new Error('kaboom')\n  const stream = fs.createWriteStream(opts.destination)\n  await once(stream, 'open')\n  return stream\n}\n\nmodule.exports = run\n"
  },
  {
    "path": "test/fixtures/to-file-transport.mjs",
    "content": "import { createWriteStream } from 'node:fs'\nimport { once } from 'node:events'\n\nexport default async function run (opts) {\n  const stream = createWriteStream(opts.destination)\n  await once(stream, 'open')\n  return stream\n}\n"
  },
  {
    "path": "test/fixtures/transport/index.js",
    "content": "'use strict'\n\nconst fs = require('node:fs')\nconst { once } = require('node:events')\n\nasync function run (opts) {\n  const stream = fs.createWriteStream(opts.destination)\n  await once(stream, 'open')\n  return stream\n}\n\nmodule.exports = run\n"
  },
  {
    "path": "test/fixtures/transport/package.json",
    "content": "{\n  \"name\": \"transport\",\n  \"version\": \"0.0.1\",\n  \"main\": \"./index.js\"\n}\n"
  },
  {
    "path": "test/fixtures/transport-exit-immediately-with-async-dest.js",
    "content": "'use strict'\n\nconst pino = require('../..')\nconst transport = pino.transport({\n  target: './to-file-transport-with-transform.js',\n  options: {\n    destination: process.argv[2]\n  }\n})\nconst logger = pino(transport)\n\nlogger.info('Hello')\n\nlogger.info('World')\n\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/transport-exit-immediately.js",
    "content": "'use strict'\n\nconst pino = require('../..')\nconst transport = pino.transport({\n  target: 'pino/file'\n})\nconst logger = pino(transport)\n\nlogger.info('Hello')\n\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/transport-exit-on-ready.js",
    "content": "'use strict'\n\nconst pino = require('../..')\nconst transport = pino.transport({\n  target: 'pino/file'\n})\nconst logger = pino(transport)\n\ntransport.on('ready', function () {\n  logger.info('Hello')\n  process.exit(0)\n})\n"
  },
  {
    "path": "test/fixtures/transport-invalid-node-options.js",
    "content": "'use strict'\n\nconst pino = require('../../')\nconst { join } = require('node:path')\n\nconst destination = process.argv[2]\n\nprocess.env.NODE_OPTIONS = `--require ${join(__dirname, 'this-file-does-not-exist.js')}`\n\nconst transport = pino.transport({\n  target: join(__dirname, 'to-file-transport.js'),\n  options: { destination }\n})\n\nconst logger = pino(transport)\ntransport.on('ready', () => {\n  logger.info('hello with invalid node options preload')\n  setTimeout(() => {\n    transport.end()\n  }, 50)\n})\n\ntransport.on('error', (err) => {\n  process.stderr.write(`${err.stack}\\n`)\n  process.exitCode = 1\n})\n"
  },
  {
    "path": "test/fixtures/transport-main.js",
    "content": "'use strict'\n\nconst { join } = require('node:path')\nconst pino = require('../..')\nconst transport = pino.transport({\n  target: join(__dirname, 'transport-worker.js')\n})\nconst logger = pino(transport)\nlogger.info('Hello')\n"
  },
  {
    "path": "test/fixtures/transport-many-lines.js",
    "content": "'use strict'\n\nconst pino = require('../..')\nconst transport = pino.transport({\n  targets: [{\n    level: 'info',\n    target: 'pino/file',\n    options: {\n      destination: process.argv[2]\n    }\n  }]\n})\nconst logger = pino(transport)\n\nconst toWrite = 1000000\ntransport.on('ready', run)\n\nlet total = 0\n\nfunction run () {\n  if (total++ === 8) {\n    return\n  }\n\n  for (let i = 0; i < toWrite; i++) {\n    logger.info(`hello ${i}`)\n  }\n  transport.once('drain', run)\n}\n"
  },
  {
    "path": "test/fixtures/transport-preload-main.mjs",
    "content": "'use strict'\n\n// This is the main script that runs after the preload\n// It imports the logger from the preload and logs a message\n\nimport { log } from './transport-preload.mjs'\n\nlog.info('hello from main')\n\n// Wait a bit for the transport to flush\nsetTimeout(() => {\n  process.exit(0)\n}, 500)\n"
  },
  {
    "path": "test/fixtures/transport-preload.mjs",
    "content": "'use strict'\n\nimport pino from '../../pino.js'\nimport { join } from 'node:path'\n\nconst log = pino({\n  transport: {\n    target: join(import.meta.dirname, 'to-file-transport.js'),\n    options: { destination: process.argv[2] }\n  }\n})\n\nexport { log }\n"
  },
  {
    "path": "test/fixtures/transport-string-stdout.js",
    "content": "'use strict'\n\nconst pino = require('../..')\nconst transport = pino.transport({\n  target: 'pino/file',\n  options: { destination: '1' }\n})\nconst logger = pino(transport)\nlogger.info('Hello')\n"
  },
  {
    "path": "test/fixtures/transport-transform.js",
    "content": "'use strict'\n\nconst build = require('pino-abstract-transport')\nconst { pipeline, Transform } = require('node:stream')\nmodule.exports = (options) => {\n  return build(function (source) {\n    const myTransportStream = new Transform({\n      autoDestroy: true,\n      objectMode: true,\n      transform (chunk, enc, cb) {\n        chunk.service = 'pino'\n        this.push(JSON.stringify(chunk))\n        cb()\n      }\n    })\n    pipeline(source, myTransportStream, () => {})\n    return myTransportStream\n  }, {\n    enablePipelining: true\n  })\n}\n"
  },
  {
    "path": "test/fixtures/transport-uses-pino-config.js",
    "content": "'use strict'\n\nconst build = require('pino-abstract-transport')\nconst { pipeline, Transform } = require('node:stream')\nmodule.exports = () => {\n  return build(function (source) {\n    const myTransportStream = new Transform({\n      autoDestroy: true,\n      objectMode: true,\n      transform (chunk, enc, cb) {\n        const {\n          time,\n          level,\n          [source.messageKey]: body,\n          [source.errorKey]: error,\n          ...attributes\n        } = chunk\n        this.push(JSON.stringify({\n          severityText: source.levels.labels[level],\n          body,\n          attributes,\n          ...(error && { error })\n        }))\n        cb()\n      }\n    })\n    pipeline(source, myTransportStream, () => {})\n    return myTransportStream\n  }, {\n    enablePipelining: true,\n    expectPinoConfig: true\n  })\n}\n"
  },
  {
    "path": "test/fixtures/transport-with-on-exit.js",
    "content": "'use strict'\nconst pino = require('../..')\nconst log = pino({\n  transport: {\n    target: 'pino/file',\n    options: { destination: 1 }\n  }\n})\nlog.info('hello world!')\nprocess.on('exit', (code) => {\n  log.info('Exiting peacefully')\n})\n"
  },
  {
    "path": "test/fixtures/transport-worker-data.js",
    "content": "'use strict'\n\nconst { parentPort, workerData } = require('worker_threads')\nconst { Writable } = require('node:stream')\n\nmodule.exports = (options) => {\n  const myTransportStream = new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      parentPort.postMessage({\n        code: 'EVENT',\n        name: 'workerData',\n        args: [workerData]\n      })\n      cb()\n    }\n  })\n  return myTransportStream\n}\n"
  },
  {
    "path": "test/fixtures/transport-worker-name.js",
    "content": "'use strict'\n\nconst { parentPort, threadName } = require('worker_threads')\nconst { Writable } = require('node:stream')\n\nlet sent = false\n\nmodule.exports = (options) => {\n  const myTransportStream = new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      if (!sent) {\n        sent = true\n        parentPort.postMessage({\n          code: 'EVENT',\n          name: 'workerThreadName',\n          args: [threadName]\n        })\n      }\n      cb()\n    }\n  })\n  return myTransportStream\n}\n"
  },
  {
    "path": "test/fixtures/transport-worker.js",
    "content": "'use strict'\n\nconst { Writable } = require('node:stream')\nconst fs = require('node:fs')\nmodule.exports = (options) => {\n  const myTransportStream = new Writable({\n    autoDestroy: true,\n    write (chunk, enc, cb) {\n      // Bypass console.log() to avoid flakiness\n      fs.writeSync(1, chunk.toString())\n      cb()\n    }\n  })\n  return myTransportStream\n}\n"
  },
  {
    "path": "test/fixtures/transport-wrong-export-type.js",
    "content": "module.exports = {\n  completelyUnrelatedProperty: 'Just a very incorrect transport worker implementation'\n}\n"
  },
  {
    "path": "test/fixtures/ts/to-file-transport-native.mts",
    "content": "import * as fs from 'node:fs'\nimport { once } from 'node:events'\n\ninterface TransportOptions {\n  destination?: fs.PathLike\n}\n\nasync function run (opts: TransportOptions): Promise<fs.WriteStream> {\n  if (!opts.destination) throw new Error('destination is required')\n  const stream = fs.createWriteStream(opts.destination, { encoding: 'utf8' })\n  await once(stream, 'open')\n  return stream\n}\n\nexport default run\n"
  },
  {
    "path": "test/fixtures/ts/to-file-transport-with-transform.ts",
    "content": "import * as fs from 'node:fs'\nimport { once } from 'node:events'\nimport { Transform } from 'node:stream'\n\nasync function run (opts: { destination?: fs.PathLike }): Promise<Transform> {\n  if (!opts.destination) throw new Error('kaboom')\n  const stream = fs.createWriteStream(opts.destination)\n  await once(stream, 'open')\n  const t = new Transform({\n    transform (chunk, enc, cb) {\n      setImmediate(cb, null, chunk.toString().toUpperCase())\n    }\n  })\n  t.pipe(stream)\n  return t\n}\n\nexport default run\n"
  },
  {
    "path": "test/fixtures/ts/to-file-transport.ts",
    "content": "import * as fs from 'node:fs'\nimport { once } from 'node:events'\n\nasync function run (opts: { destination?: fs.PathLike }): Promise<fs.WriteStream> {\n  if (!opts.destination) throw new Error('kaboom')\n  const stream = fs.createWriteStream(opts.destination, { encoding: 'utf8' })\n  await once(stream, 'open')\n  return stream\n}\n\nexport default run\n"
  },
  {
    "path": "test/fixtures/ts/transpile.cjs",
    "content": "#!/usr/bin/env node\n\nconst execa = require('execa')\nconst fs = require('node:fs')\n\nconst existsSync = fs.existsSync\nconst stat = fs.promises.stat\n\n// Hardcoded parameters\nconst esVersions = ['es5', 'es6', 'es2017', 'esnext']\nconst filesToTranspile = ['to-file-transport.ts']\n\nasync function transpile () {\n  process.chdir(__dirname)\n\n  for (const sourceFileName of filesToTranspile) {\n    const sourceStat = await stat(sourceFileName)\n\n    for (const esVersion of esVersions) {\n      const intermediateFileName = sourceFileName.replace(/\\.ts$/, '.js')\n      const targetFileName = sourceFileName.replace(/\\.ts$/, `.${esVersion}.cjs`)\n\n      const shouldTranspile = !existsSync(targetFileName) || (await stat(targetFileName)).mtimeMs < sourceStat.mtimeMs\n\n      if (shouldTranspile) {\n        await execa('tsc', ['--target', esVersion, '--module', 'commonjs', sourceFileName])\n        await execa('mv', [intermediateFileName, targetFileName])\n      }\n    }\n  }\n}\n\ntranspile().catch(err => {\n  process.exitCode = 1\n  throw err\n})\n"
  },
  {
    "path": "test/fixtures/ts/transport-exit-immediately-with-async-dest.ts",
    "content": "import pino from '../../..'\nimport { join } from 'node:path'\n\nconst transport = pino.transport({\n  target: join(__dirname, 'to-file-transport-with-transform.ts'),\n  options: {\n    destination: process.argv[2]\n  }\n})\nconst logger = pino(transport)\n\nlogger.info('Hello')\nlogger.info('World')\n\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/ts/transport-exit-immediately.ts",
    "content": "import pino from '../../..'\n\nconst transport = pino.transport({\n  target: 'pino/file'\n})\nconst logger = pino(transport)\n\nlogger.info('Hello')\n\nprocess.exit(0)\n"
  },
  {
    "path": "test/fixtures/ts/transport-exit-on-ready.ts",
    "content": "import pino from '../../..'\n\nconst transport = pino.transport({\n  target: 'pino/file'\n})\nconst logger = pino(transport)\n\ntransport.on('ready', function () {\n  logger.info('Hello')\n  process.exit(0)\n})\n"
  },
  {
    "path": "test/fixtures/ts/transport-main.ts",
    "content": "import { join } from 'node:path'\nimport pino from '../../..'\n\nconst transport = pino.transport({\n  target: join(__dirname, 'transport-worker.ts')\n})\nconst logger = pino(transport)\nlogger.info('Hello')\n"
  },
  {
    "path": "test/fixtures/ts/transport-string-stdout.ts",
    "content": "import pino from '../../..'\n\nconst transport = pino.transport({\n  target: 'pino/file',\n  options: { destination: '1' }\n})\nconst logger = pino(transport)\nlogger.info('Hello')\n"
  },
  {
    "path": "test/fixtures/ts/transport-worker.ts",
    "content": "import { Writable } from 'node:stream'\n\nexport default (): Writable => {\n  const myTransportStream = new Writable({\n    autoDestroy: true,\n    write (chunk, _enc, cb) {\n      console.log(chunk.toString())\n      cb()\n    },\n    defaultEncoding: 'utf8'\n  })\n\n  return myTransportStream\n}\n"
  },
  {
    "path": "test/formatters.test.js",
    "content": "'use strict'\n/* eslint no-prototype-builtins: 0 */\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { hostname } = require('node:os')\nconst { join } = require('node:path')\nconst { readFile } = require('node:fs').promises\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, match, once, watchFileCreated, file } = require('./helper')\nconst pino = require('../')\n\ntest('level formatter', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      level (label, number) {\n        return {\n          log: {\n            level: label\n          }\n        }\n      }\n    }\n  }, stream)\n\n  const o = once(stream, 'data')\n  logger.info('hello world')\n  match(await o, {\n    log: {\n      level: 'info'\n    }\n  })\n})\n\ntest('bindings formatter', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      bindings (bindings) {\n        return {\n          process: {\n            pid: bindings.pid\n          },\n          host: {\n            name: bindings.hostname\n          }\n        }\n      }\n    }\n  }, stream)\n\n  const o = once(stream, 'data')\n  logger.info('hello world')\n  match(await o, {\n    process: {\n      pid: process.pid\n    },\n    host: {\n      name: hostname()\n    }\n  })\n})\n\ntest('no bindings formatter', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      bindings (bindings) {\n        return null\n      }\n    }\n  }, stream)\n\n  const o = once(stream, 'data')\n  logger.info('hello world')\n  const log = await o\n  assert.equal(log.hasOwnProperty('pid'), false)\n  assert.equal(log.hasOwnProperty('hostname'), false)\n  match(log, { msg: 'hello world' })\n})\n\ntest('log formatter', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      log (obj) {\n        plan.equal(obj.hasOwnProperty('msg'), false)\n        return { hello: 'world', ...obj }\n      }\n    }\n  }, stream)\n\n  const o = once(stream, 'data')\n  logger.info({ foo: 'bar', nested: { object: true } }, 'hello world')\n  match(await o, {\n    hello: 'world',\n    foo: 'bar',\n    nested: { object: true }\n  })\n\n  await plan\n})\n\ntest('Formatters combined', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      level (label, number) {\n        return {\n          log: {\n            level: label\n          }\n        }\n      },\n      bindings (bindings) {\n        return {\n          process: {\n            pid: bindings.pid\n          },\n          host: {\n            name: bindings.hostname\n          }\n        }\n      },\n      log (obj) {\n        return { hello: 'world', ...obj }\n      }\n    }\n  }, stream)\n\n  const o = once(stream, 'data')\n  logger.info({ foo: 'bar', nested: { object: true } }, 'hello world')\n  match(await o, {\n    log: {\n      level: 'info'\n    },\n    process: {\n      pid: process.pid\n    },\n    host: {\n      name: hostname()\n    },\n    hello: 'world',\n    foo: 'bar',\n    nested: { object: true }\n  })\n})\n\ntest('Formatters in child logger', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      level (label, number) {\n        return {\n          log: {\n            level: label\n          }\n        }\n      },\n      bindings (bindings) {\n        return {\n          process: {\n            pid: bindings.pid\n          },\n          host: {\n            name: bindings.hostname\n          }\n        }\n      },\n      log (obj) {\n        return { hello: 'world', ...obj }\n      }\n    }\n  }, stream)\n\n  const child = logger.child({\n    foo: 'bar',\n    nested: { object: true }\n  }, {\n    formatters: {\n      bindings (bindings) {\n        return { ...bindings, faz: 'baz' }\n      }\n    }\n  })\n\n  const o = once(stream, 'data')\n  child.info('hello world')\n  match(await o, {\n    log: {\n      level: 'info'\n    },\n    process: {\n      pid: process.pid\n    },\n    host: {\n      name: hostname()\n    },\n    hello: 'world',\n    foo: 'bar',\n    nested: { object: true },\n    faz: 'baz'\n  })\n})\n\ntest('Formatters without bindings in child logger', async () => {\n  const stream = sink()\n  const logger = pino({\n    formatters: {\n      level (label, number) {\n        return {\n          log: {\n            level: label\n          }\n        }\n      },\n      bindings (bindings) {\n        return {\n          process: {\n            pid: bindings.pid\n          },\n          host: {\n            name: bindings.hostname\n          }\n        }\n      },\n      log (obj) {\n        return { hello: 'world', ...obj }\n      }\n    }\n  }, stream)\n\n  const child = logger.child({\n    foo: 'bar',\n    nested: { object: true }\n  }, {\n    formatters: {\n      log (obj) {\n        return { other: 'stuff', ...obj }\n      }\n    }\n  })\n\n  const o = once(stream, 'data')\n  child.info('hello world')\n  match(await o, {\n    log: {\n      level: 'info'\n    },\n    process: {\n      pid: process.pid\n    },\n    host: {\n      name: hostname()\n    },\n    foo: 'bar',\n    other: 'stuff',\n    nested: { object: true }\n  })\n})\n\ntest('elastic common schema format', async () => {\n  const stream = sink()\n  const ecs = {\n    formatters: {\n      level (label, number) {\n        return {\n          log: {\n            level: label,\n            logger: 'pino'\n          }\n        }\n      },\n      bindings (bindings) {\n        return {\n          process: {\n            pid: bindings.pid\n          },\n          host: {\n            name: bindings.hostname\n          }\n        }\n      },\n      log (obj) {\n        return { ecs: { version: '1.4.0' }, ...obj }\n      }\n    },\n    messageKey: 'message',\n    timestamp: () => `,\"@timestamp\":\"${new Date(Date.now()).toISOString()}\"`\n  }\n\n  const logger = pino({ ...ecs }, stream)\n\n  const o = once(stream, 'data')\n  logger.info({ foo: 'bar' }, 'hello world')\n  const log = await o\n  assert.equal(typeof log['@timestamp'], 'string')\n  match(log, {\n    log: { level: 'info', logger: 'pino' },\n    process: { pid: process.pid },\n    host: { name: hostname() },\n    ecs: { version: '1.4.0' },\n    foo: 'bar',\n    message: 'hello world'\n  })\n})\n\ntest('formatter with transport', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const destination = file()\n  const logger = pino({\n    formatters: {\n      log (obj) {\n        plan.equal(obj.hasOwnProperty('msg'), false)\n        return { hello: 'world', ...obj }\n      }\n    },\n    transport: {\n      targets: [\n        {\n          target: join(__dirname, 'fixtures', 'to-file-transport.js'),\n          options: { destination }\n        }\n      ]\n    }\n  })\n\n  logger.info({ foo: 'bar', nested: { object: true } }, 'hello world')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  match(result, {\n    hello: 'world',\n    foo: 'bar',\n    nested: { object: true }\n  })\n})\n\ntest('throws when custom level formatter is used with transport.targets', async () => {\n  assert.throws(\n    () => {\n      pino({\n        formatters: {\n          level (label) {\n            return label\n          }\n        },\n        transport: {\n          targets: [\n            {\n              target: 'pino/file',\n              options: { destination: 'foo.log' }\n            }\n          ]\n        }\n      }\n      )\n    },\n    Error('option.transport.targets do not allow custom level formatters')\n  )\n})\n"
  },
  {
    "path": "test/helper.d.ts",
    "content": "import type { PathLike } from 'node:fs'\n\nexport declare function watchFileCreated (filename: PathLike): Promise<void>\nexport declare function watchForWrite (filename: PathLike, testString: string): Promise<void>\n"
  },
  {
    "path": "test/helper.js",
    "content": "'use strict'\n\nconst crypto = require('node:crypto')\nconst { join } = require('node:path')\nconst os = require('node:os')\nconst { existsSync, readFileSync, statSync, unlinkSync } = require('node:fs')\nconst writer = require('flush-write-stream')\nconst split = require('split2')\n\nconst pid = process.pid\nconst hostname = os.hostname()\nconst { tmpdir } = os\n\nconst isWin = process.platform === 'win32'\nconst isYarnPnp = process.versions.pnp !== undefined\n\nfunction getPathToNull () {\n  return isWin ? '\\\\\\\\.\\\\NUL' : '/dev/null'\n}\n\nfunction once (emitter, name) {\n  return new Promise((resolve, reject) => {\n    if (name !== 'error') emitter.once('error', reject)\n    emitter.once(name, (...args) => {\n      emitter.removeListener('error', reject)\n      resolve(...args)\n    })\n  })\n}\n\nfunction sink (func) {\n  const result = split((data) => {\n    try {\n      return JSON.parse(data)\n    } catch (err) {\n      console.log(err)\n      console.log(data)\n    }\n  })\n  if (func) result.pipe(writer.obj(func))\n  return result\n}\n\nfunction check (is, chunk, level, msg) {\n  is(new Date(chunk.time) <= new Date(), true, 'time is greater than Date.now()')\n  delete chunk.time\n  is(chunk.pid, pid)\n  is(chunk.hostname, hostname)\n  is(chunk.level, level)\n  is(chunk.msg, msg)\n}\n\nfunction sleep (ms) {\n  return new Promise((resolve) => {\n    setTimeout(resolve, ms)\n  })\n}\n\nfunction watchFileCreated (filename) {\n  return new Promise((resolve, reject) => {\n    const TIMEOUT = process.env.PINO_TEST_WAIT_WATCHFILE_TIMEOUT || 10000\n    const INTERVAL = 100\n    const threshold = TIMEOUT / INTERVAL\n    let counter = 0\n    const interval = setInterval(() => {\n      const exists = existsSync(filename)\n      // On some CI runs file is created but not filled\n      if (exists && statSync(filename).size !== 0) {\n        clearInterval(interval)\n        resolve()\n      } else if (counter <= threshold) {\n        counter++\n      } else {\n        clearInterval(interval)\n        reject(new Error(\n          `${filename} hasn't been created within ${TIMEOUT} ms. ` +\n          (exists ? 'File exist, but still empty.' : 'File not yet created.')\n        ))\n      }\n    }, INTERVAL)\n  })\n}\n\nfunction watchForWrite (filename, testString) {\n  return new Promise((resolve, reject) => {\n    const TIMEOUT = process.env.PINO_TEST_WAIT_WRITE_TIMEOUT || 10000\n    const INTERVAL = 100\n    const threshold = TIMEOUT / INTERVAL\n    let counter = 0\n    const interval = setInterval(() => {\n      if (readFileSync(filename).includes(testString)) {\n        clearInterval(interval)\n        resolve()\n      } else if (counter <= threshold) {\n        counter++\n      } else {\n        clearInterval(interval)\n        reject(new Error(`'${testString}' hasn't been written to ${filename} within ${TIMEOUT} ms.`))\n      }\n    }, INTERVAL)\n  })\n}\n\nlet files = []\n\nfunction file () {\n  const hash = crypto.randomBytes(12).toString('hex')\n  const file = join(tmpdir(), `pino-${pid}-${hash}`)\n  files.push(file)\n  return file\n}\n\nprocess.on('beforeExit', () => {\n  if (files.length === 0) return\n  for (const file of files) {\n    try {\n      unlinkSync(file)\n    } catch (e) {\n    }\n  }\n  files = []\n})\n\n/**\n * match is a bare-bones object shape matcher. We should be able to replace\n * this with `assert.partialDeepStrictEqual` when v22 is our minimum.\n *\n * @param {object} found\n * @param {object} expected\n */\nfunction match (found, expected) {\n  for (const [key, value] of Object.entries(expected)) {\n    if (Object.prototype.toString.call(value) === '[object Object]') {\n      match(found[key], value)\n      continue\n    }\n    if (value !== found[key]) {\n      throw Error(`expected \"${value}\" but found \"${found[key]}\"`)\n    }\n  }\n}\n\nmodule.exports = {\n  check,\n  file,\n  getPathToNull,\n  isWin,\n  isYarnPnp,\n  match,\n  once,\n  sink,\n  sleep,\n  watchFileCreated,\n  watchForWrite\n}\n"
  },
  {
    "path": "test/hooks.test.js",
    "content": "'use strict'\n\nconst { describe, test } = require('node:test')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, match, once } = require('./helper')\nconst pino = require('../')\n\ndescribe('log method hook', () => {\n  test('gets invoked', async t => {\n    const plan = tspl(t, { plan: 7 })\n\n    const stream = sink()\n    const logger = pino({\n      hooks: {\n        logMethod (args, method, level) {\n          plan.equal(Array.isArray(args), true)\n          plan.equal(typeof level, 'number')\n          plan.equal(args.length, 3)\n          plan.equal(level, this.levels.values.info)\n          plan.deepEqual(args, ['a', 'b', 'c'])\n\n          plan.equal(typeof method, 'function')\n          plan.equal(method.name, 'LOG')\n\n          method.apply(this, [args.join('-')])\n        }\n      }\n    }, stream)\n\n    const o = once(stream, 'data')\n    logger.info('a', 'b', 'c')\n    match(await o, { msg: 'a-b-c' })\n  })\n\n  test('fatal method invokes hook', async t => {\n    const plan = tspl(t, { plan: 1 })\n\n    const stream = sink()\n    const logger = pino({\n      hooks: {\n        logMethod (args, method) {\n          plan.ok(true)\n          method.apply(this, [args.join('-')])\n        }\n      }\n    }, stream)\n\n    const o = once(stream, 'data')\n    logger.fatal('a')\n    match(await o, { msg: 'a' })\n  })\n\n  test('children get the hook', async t => {\n    const plan = tspl(t, { plan: 2 })\n\n    const stream = sink()\n    const root = pino({\n      hooks: {\n        logMethod (args, method) {\n          plan.ok(true)\n          method.apply(this, [args.join('-')])\n        }\n      }\n    }, stream)\n    const child = root.child({ child: 'one' })\n    const grandchild = child.child({ child: 'two' })\n\n    let o = once(stream, 'data')\n    child.info('a', 'b')\n    match(await o, { msg: 'a-b' })\n\n    o = once(stream, 'data')\n    grandchild.info('c', 'd')\n    match(await o, { msg: 'c-d' })\n  })\n\n  test('get log level', async t => {\n    const plan = tspl(t, { plan: 2 })\n\n    const stream = sink()\n    const logger = pino({\n      hooks: {\n        logMethod (args, method, level) {\n          plan.equal(typeof level, 'number')\n          plan.equal(level, this.levels.values.error)\n\n          method.apply(this, [args.join('-')])\n        }\n      }\n    }, stream)\n\n    const o = once(stream, 'data')\n    logger.error('a')\n    match(await o, { msg: 'a' })\n  })\n})\n\ndescribe('streamWrite hook', () => {\n  test('gets invoked', async () => {\n    const stream = sink()\n    const logger = pino({\n      hooks: {\n        streamWrite (s) {\n          return s.replaceAll('redact-me', 'XXX')\n        }\n      }\n    }, stream)\n\n    const o = once(stream, 'data')\n    logger.info('hide redact-me in this string')\n    match(await o, { msg: 'hide XXX in this string' })\n  })\n})\n"
  },
  {
    "path": "test/http.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst http = require('node:http')\nconst os = require('node:os')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('http request support', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  let originalReq\n  const instance = pino(sink((chunk, enc) => {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.deepEqual(chunk, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'my request',\n      req: {\n        method: originalReq.method,\n        url: originalReq.url,\n        headers: originalReq.headers,\n        remoteAddress: originalReq.socket.remoteAddress,\n        remotePort: originalReq.socket.remotePort\n      }\n    })\n  }))\n\n  const server = http.createServer((req, res) => {\n    originalReq = req\n    instance.info(req, 'my request')\n    res.end('hello')\n  })\n  server.unref()\n  server.listen()\n  const err = await once(server, 'listening')\n  plan.equal(err, undefined)\n  const res = await once(http.get('http://localhost:' + server.address().port), 'response')\n  res.resume()\n  server.close()\n\n  await plan\n})\n\ntest('http request support via serializer', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  let originalReq\n  const instance = pino({\n    serializers: {\n      req: pino.stdSerializers.req\n    }\n  }, sink((chunk, enc) => {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.deepEqual(chunk, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'my request',\n      req: {\n        method: originalReq.method,\n        url: originalReq.url,\n        headers: originalReq.headers,\n        remoteAddress: originalReq.socket.remoteAddress,\n        remotePort: originalReq.socket.remotePort\n      }\n    })\n  }))\n\n  const server = http.createServer(function (req, res) {\n    originalReq = req\n    instance.info({ req }, 'my request')\n    res.end('hello')\n  })\n  server.unref()\n  server.listen()\n  const err = await once(server, 'listening')\n  plan.equal(err, undefined)\n\n  const res = await once(http.get('http://localhost:' + server.address().port), 'response')\n  res.resume()\n  server.close()\n\n  await plan\n})\n\ntest('http response support', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  let originalRes\n  const instance = pino(sink((chunk, enc) => {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.deepEqual(chunk, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'my response',\n      res: {\n        statusCode: originalRes.statusCode,\n        headers: originalRes.getHeaders()\n      }\n    })\n  }))\n\n  const server = http.createServer(function (req, res) {\n    originalRes = res\n    res.end('hello')\n    instance.info(res, 'my response')\n  })\n  server.unref()\n  server.listen()\n  const err = await once(server, 'listening')\n\n  plan.equal(err, undefined)\n\n  const res = await once(http.get('http://localhost:' + server.address().port), 'response')\n  res.resume()\n  server.close()\n\n  await plan\n})\n\ntest('http response support via a serializer', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const instance = pino({\n    serializers: {\n      res: pino.stdSerializers.res\n    }\n  }, sink((chunk, enc) => {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.deepEqual(chunk, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'my response',\n      res: {\n        statusCode: 200,\n        headers: {\n          'x-single': 'y',\n          'x-multi': [1, 2]\n        }\n      }\n    })\n  }))\n\n  const server = http.createServer(function (req, res) {\n    res.setHeader('x-single', 'y')\n    res.setHeader('x-multi', [1, 2])\n    res.end('hello')\n    instance.info({ res }, 'my response')\n  })\n\n  server.unref()\n  server.listen()\n  const err = await once(server, 'listening')\n  plan.equal(err, undefined)\n\n  const res = await once(http.get('http://localhost:' + server.address().port), 'response')\n  res.resume()\n  server.close()\n\n  await plan\n})\n\ntest('http request support via serializer in a child', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  let originalReq\n  const instance = pino({\n    serializers: {\n      req: pino.stdSerializers.req\n    }\n  }, sink((chunk, enc) => {\n    plan.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')\n    delete chunk.time\n    plan.deepEqual(chunk, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'my request',\n      req: {\n        method: originalReq.method,\n        url: originalReq.url,\n        headers: originalReq.headers,\n        remoteAddress: originalReq.socket.remoteAddress,\n        remotePort: originalReq.socket.remotePort\n      }\n    })\n  }))\n\n  const server = http.createServer(function (req, res) {\n    originalReq = req\n    const child = instance.child({ req })\n    child.info('my request')\n    res.end('hello')\n  })\n\n  server.unref()\n  server.listen()\n  const err = await once(server, 'listening')\n  plan.equal(err, undefined)\n\n  const res = await once(http.get('http://localhost:' + server.address().port), 'response')\n  res.resume()\n  server.close()\n\n  await plan\n})\n"
  },
  {
    "path": "test/internals/version.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst fs = require('node:fs')\nconst path = require('node:path')\n\nconst pino = require('../..')()\n\ntest('should be the same as package.json', () => {\n  const json = JSON.parse(\n    fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'))\n      .toString('utf8')\n  )\n\n  assert.equal(pino.version, json.version)\n})\n"
  },
  {
    "path": "test/is-level-enabled.test.js",
    "content": "'use strict'\n\nconst { describe, test } = require('node:test')\nconst assert = require('node:assert')\n\nconst pino = require('../')\n\nconst descLevels = {\n  trace: 60,\n  debug: 50,\n  info: 40,\n  warn: 30,\n  error: 20,\n  fatal: 10\n}\n\nconst ascLevels = {\n  trace: 10,\n  debug: 20,\n  info: 30,\n  warn: 40,\n  error: 50,\n  fatal: 60\n}\n\ndescribe('Default levels suite', () => {\n  test('can check if current level enabled', async () => {\n    const log = pino({ level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if level enabled after level set', async () => {\n    const log = pino()\n    assert.equal(false, log.isLevelEnabled('debug'))\n    log.level = 'debug'\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if higher level enabled', async () => {\n    const log = pino({ level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('error'))\n  })\n\n  test('can check if lower level is disabled', async () => {\n    const log = pino({ level: 'error' })\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('ASC: can check if child has current level enabled', async () => {\n    const log = pino().child({}, { level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if custom level is enabled', async () => {\n    const log = pino({\n      customLevels: { foo: 35 },\n      level: 'debug'\n    })\n    assert.equal(true, log.isLevelEnabled('foo'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n})\n\ndescribe('Ascending levels suite', () => {\n  const customLevels = ascLevels\n  const levelComparison = 'ASC'\n\n  test('can check if current level enabled', async () => {\n    const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if level enabled after level set', async () => {\n    const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(false, log.isLevelEnabled('debug'))\n    log.level = 'debug'\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if higher level enabled', async () => {\n    const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(true, log.isLevelEnabled('error'))\n  })\n\n  test('can check if lower level is disabled', async () => {\n    const log = pino({ level: 'error', customLevels, useOnlyCustomLevels: true })\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if child has current level enabled', async () => {\n    const log = pino().child({ levelComparison, customLevels, useOnlyCustomLevels: true }, { level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if custom level is enabled', async () => {\n    const log = pino({\n      levelComparison,\n      useOnlyCustomLevels: true,\n      customLevels: { foo: 35, ...customLevels },\n      level: 'debug'\n    })\n    assert.equal(true, log.isLevelEnabled('foo'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n})\n\ndescribe('Descending levels suite', () => {\n  const customLevels = descLevels\n  const levelComparison = 'DESC'\n\n  test('can check if current level enabled', async () => {\n    const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if level enabled after level set', async () => {\n    const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(false, log.isLevelEnabled('debug'))\n    log.level = 'debug'\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('can check if higher level enabled', async () => {\n    const log = pino({ level: 'debug', levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(true, log.isLevelEnabled('error'))\n  })\n\n  test('can check if lower level is disabled', async () => {\n    const log = pino({ level: 'error', levelComparison, customLevels, useOnlyCustomLevels: true })\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if child has current level enabled', async () => {\n    const log = pino({ levelComparison, customLevels, useOnlyCustomLevels: true }).child({}, { level: 'debug' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n\n  test('can check if custom level is enabled', async () => {\n    const log = pino({\n      levelComparison,\n      customLevels: { foo: 35, ...customLevels },\n      useOnlyCustomLevels: true,\n      level: 'debug'\n    })\n    assert.equal(true, log.isLevelEnabled('foo'))\n    assert.equal(true, log.isLevelEnabled('error'))\n    assert.equal(false, log.isLevelEnabled('trace'))\n  })\n})\n\ndescribe('Custom levels comparison', () => {\n  test('Custom comparison returns true cause level is enabled', async () => {\n    const log = pino({ level: 'error', levelComparison: () => true })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('Custom comparison returns false cause level is disabled', async () => {\n    const log = pino({ level: 'error', levelComparison: () => false })\n    assert.equal(false, log.isLevelEnabled('debug'))\n  })\n\n  test('Custom comparison returns true cause child level is enabled', async () => {\n    const log = pino({ levelComparison: () => true }).child({ level: 'error' })\n    assert.equal(true, log.isLevelEnabled('debug'))\n  })\n\n  test('Custom comparison returns false cause child level is disabled', async () => {\n    const log = pino({ levelComparison: () => false }).child({ level: 'error' })\n    assert.equal(false, log.isLevelEnabled('debug'))\n  })\n})\n"
  },
  {
    "path": "test/jest/basic.spec.js",
    "content": "/* global test */\nconst pino = require('../../pino')\n\ntest('transport should work in jest', function () {\n  pino({\n    transport: {\n      target: 'pino-pretty'\n    }\n  })\n})\n"
  },
  {
    "path": "test/levels.test.js",
    "content": "'use strict'\n\nconst { describe, test } = require('node:test')\nconst assert = require('node:assert')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, once, check } = require('./helper')\nconst pino = require('../')\n\nconst levelsLib = require('../lib/levels')\n\n// Silence all warnings for this test\nprocess.removeAllListeners('warning')\nprocess.on('warning', () => {})\n\ntest('set the level by string', async () => {\n  const expected = [{\n    level: 50,\n    msg: 'this is an error'\n  }, {\n    level: 60,\n    msg: 'this is fatal'\n  }]\n  const stream = sink()\n  const instance = pino(stream)\n  instance.level = 'error'\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  const current = expected.shift()\n  check(assert.equal, result, current.level, current.msg)\n})\n\ntest('the wrong level throws', async () => {\n  const instance = pino()\n  assert.throws(() => {\n    instance.level = 'kaboom'\n  })\n})\n\ntest('set the level by number', async () => {\n  const expected = [{\n    level: 50,\n    msg: 'this is an error'\n  }, {\n    level: 60,\n    msg: 'this is fatal'\n  }]\n  const stream = sink()\n  const instance = pino(stream)\n\n  instance.level = 50\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  const current = expected.shift()\n  check(assert.equal, result, current.level, current.msg)\n})\n\ntest('exposes level string mappings', async () => {\n  assert.equal(pino.levels.values.error, 50)\n})\n\ntest('exposes level number mappings', async () => {\n  assert.equal(pino.levels.labels[50], 'error')\n})\n\ntest('returns level integer', async () => {\n  const instance = pino({ level: 'error' })\n  assert.equal(instance.levelVal, 50)\n})\n\ntest('child returns level integer', async () => {\n  const parent = pino({ level: 'error' })\n  const child = parent.child({ foo: 'bar' })\n  assert.equal(child.levelVal, 50)\n})\n\ntest('set the level via exported pino function', async () => {\n  const expected = [{\n    level: 50,\n    msg: 'this is an error'\n  }, {\n    level: 60,\n    msg: 'this is fatal'\n  }]\n  const stream = sink()\n  const instance = pino({ level: 'error' }, stream)\n\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n  const result = await once(stream, 'data')\n  const current = expected.shift()\n  check(assert.equal, result, current.level, current.msg)\n})\n\ntest('level-change event', async (t) => {\n  const plan = tspl(t, { plan: 8 })\n  const instance = pino()\n  function handle (lvl, val, prevLvl, prevVal, logger) {\n    plan.equal(lvl, 'trace')\n    plan.equal(val, 10)\n    plan.equal(prevLvl, 'info')\n    plan.equal(prevVal, 30)\n    plan.equal(logger, instance)\n  }\n  instance.on('level-change', handle)\n  instance.level = 'trace'\n  instance.removeListener('level-change', handle)\n  instance.level = 'info'\n\n  let count = 0\n\n  const l1 = () => count++\n  const l2 = () => count++\n  const l3 = () => count++\n  instance.on('level-change', l1)\n  instance.on('level-change', l2)\n  instance.on('level-change', l3)\n\n  instance.level = 'trace'\n  instance.removeListener('level-change', l3)\n  instance.level = 'fatal'\n  instance.removeListener('level-change', l1)\n  instance.level = 'debug'\n  instance.removeListener('level-change', l2)\n  instance.level = 'info'\n\n  plan.equal(count, 6)\n\n  instance.once('level-change', (lvl, val, prevLvl, prevVal, logger) => plan.equal(logger, instance))\n  instance.level = 'info'\n  const child = instance.child({})\n  instance.once('level-change', (lvl, val, prevLvl, prevVal, logger) => plan.equal(logger, child))\n  child.level = 'trace'\n\n  await plan\n})\n\ntest('enable', async (t) => {\n  const instance = pino({\n    level: 'trace',\n    enabled: false\n  }, sink((result, enc) => {\n    throw Error('no data should be logged')\n  }))\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    instance[level]('hello world')\n  })\n})\n\ntest('silent level', async () => {\n  const instance = pino({\n    level: 'silent'\n  }, sink((result, enc) => {\n    throw Error('no data should be logged')\n  }))\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    instance[level]('hello world')\n  })\n})\n\ntest('set silent via Infinity', async () => {\n  const instance = pino({\n    level: Infinity\n  }, sink((result, enc) => {\n    throw Error('no data should be logged')\n  }))\n\n  Object.keys(pino.levels.values).forEach((level) => {\n    instance[level]('hello world')\n  })\n})\n\ntest('exposed levels', async () => {\n  assert.deepEqual(Object.keys(pino.levels.values), [\n    'trace',\n    'debug',\n    'info',\n    'warn',\n    'error',\n    'fatal'\n  ])\n})\n\ntest('exposed labels', async () => {\n  assert.deepEqual(Object.keys(pino.levels.labels), [\n    '10',\n    '20',\n    '30',\n    '40',\n    '50',\n    '60'\n  ])\n})\n\ntest('setting level in child', async (t) => {\n  const plan = tspl(t, { plan: 10 })\n  const expected = [{\n    level: 50,\n    msg: 'this is an error'\n  }, {\n    level: 60,\n    msg: 'this is fatal'\n  }]\n  const instance = pino(sink((result, enc, cb) => {\n    const current = expected.shift()\n    check(plan.equal, result, current.level, current.msg)\n    cb()\n  })).child({ level: 30 })\n\n  instance.level = 'error'\n  instance.info('hello world')\n  instance.error('this is an error')\n  instance.fatal('this is fatal')\n\n  await plan\n})\n\ntest('setting level by assigning a number to level', async () => {\n  const instance = pino()\n  assert.equal(instance.levelVal, 30)\n  assert.equal(instance.level, 'info')\n  instance.level = 50\n  assert.equal(instance.levelVal, 50)\n  assert.equal(instance.level, 'error')\n})\n\ntest('setting level by number to unknown value results in a throw', async () => {\n  const instance = pino()\n  assert.throws(() => { instance.level = 973 })\n})\n\ntest('setting level by assigning a known label to level', async () => {\n  const instance = pino()\n  assert.equal(instance.levelVal, 30)\n  assert.equal(instance.level, 'info')\n  instance.level = 'error'\n  assert.equal(instance.levelVal, 50)\n  assert.equal(instance.level, 'error')\n})\n\ntest('levelVal is read only', async () => {\n  const instance = pino()\n  assert.throws(() => { instance.levelVal = 20 })\n})\n\ntest('produces labels when told to', async (t) => {\n  const plan = tspl(t, { plan: 5 })\n  const expected = [{\n    level: 'info',\n    msg: 'hello world'\n  }]\n  const instance = pino({\n    formatters: {\n      level (label, number) {\n        return { level: label }\n      }\n    }\n  }, sink((result, enc, cb) => {\n    const current = expected.shift()\n    check(plan.equal, result, current.level, current.msg)\n    cb()\n  }))\n\n  instance.info('hello world')\n\n  await plan\n})\n\ntest('resets levels from labels to numbers', async (t) => {\n  const plan = tspl(t, { plan: 5 })\n  const expected = [{\n    level: 30,\n    msg: 'hello world'\n  }]\n  pino({ useLevelLabels: true })\n  const instance = pino({ useLevelLabels: false }, sink((result, enc, cb) => {\n    const current = expected.shift()\n    check(plan.equal, result, current.level, current.msg)\n    cb()\n  }))\n\n  instance.info('hello world')\n\n  await plan\n})\n\ntest('changes label naming when told to', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const expected = [{\n    priority: 30,\n    msg: 'hello world'\n  }]\n  const instance = pino({\n    formatters: {\n      level (label, number) {\n        return { priority: number }\n      }\n    }\n  }, sink((result, enc, cb) => {\n    const current = expected.shift()\n    plan.equal(result.priority, current.priority)\n    plan.equal(result.msg, current.msg)\n    cb()\n  }))\n\n  instance.info('hello world')\n\n  await plan\n})\n\ntest('children produce labels when told to', async (t) => {\n  const plan = tspl(t, { plan: 10 })\n  const expected = [\n    {\n      level: 'info',\n      msg: 'child 1'\n    },\n    {\n      level: 'info',\n      msg: 'child 2'\n    }\n  ]\n  const instance = pino({\n    formatters: {\n      level (label, number) {\n        return { level: label }\n      }\n    }\n  }, sink((result, enc, cb) => {\n    const current = expected.shift()\n    check(plan.equal, result, current.level, current.msg)\n    cb()\n  }))\n\n  const child1 = instance.child({ name: 'child1' })\n  const child2 = child1.child({ name: 'child2' })\n\n  child1.info('child 1')\n  child2.info('child 2')\n\n  await plan\n})\n\ntest('produces labels for custom levels', async (t) => {\n  const plan = tspl(t, { plan: 10 })\n  const expected = [\n    {\n      level: 'info',\n      msg: 'hello world'\n    },\n    {\n      level: 'foo',\n      msg: 'foobar'\n    }\n  ]\n  const opts = {\n    formatters: {\n      level (label, number) {\n        return { level: label }\n      }\n    },\n    customLevels: {\n      foo: 35\n    }\n  }\n  const instance = pino(opts, sink((result, enc, cb) => {\n    const current = expected.shift()\n    check(plan.equal, result, current.level, current.msg)\n    cb()\n  }))\n\n  instance.info('hello world')\n  instance.foo('foobar')\n\n  await plan\n})\n\ntest('setting levelKey does not affect labels when told to', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const instance = pino(\n    {\n      formatters: {\n        level (label, number) {\n          return { priority: label }\n        }\n      }\n    },\n    sink((result, enc, cb) => {\n      plan.equal(result.priority, 'info')\n      cb()\n    })\n  )\n\n  instance.info('hello world')\n\n  await plan\n})\n\ntest('throws when creating a default label that does not exist in logger levels', async () => {\n  const defaultLevel = 'foo'\n  assert.throws(\n    () => {\n      pino({\n        customLevels: {\n          bar: 5\n        },\n        level: defaultLevel\n      })\n    },\n    Error(`default level:${defaultLevel} must be included in custom levels`)\n  )\n})\n\ntest('throws when creating a default value that does not exist in logger levels', async () => {\n  const defaultLevel = 15\n  assert.throws(\n    () => {\n      pino({\n        customLevels: {\n          bar: 5\n        },\n        level: defaultLevel\n      })\n    },\n    Error(`default level:${defaultLevel} must be included in custom levels`)\n  )\n})\n\ntest('throws when creating a default value that does not exist in logger levels', async ({ equal, throws }) => {\n  assert.throws(\n    () => {\n      pino({\n        customLevels: {\n          foo: 5\n        },\n        useOnlyCustomLevels: true\n      })\n    },\n    /default level:info must be included in custom levels/\n  )\n})\n\ntest('passes when creating a default value that exists in logger levels', async () => {\n  pino({\n    level: 30\n  })\n})\n\ntest('log null value when message is null', async () => {\n  const expected = {\n    msg: null,\n    level: 30\n  }\n\n  const stream = sink()\n  const instance = pino(stream)\n  instance.level = 'info'\n  instance.info(null)\n\n  const result = await once(stream, 'data')\n  check(assert.equal, result, expected.level, expected.msg)\n})\n\ntest('formats when base param is null', async () => {\n  const expected = {\n    msg: 'a string',\n    level: 30\n  }\n\n  const stream = sink()\n  const instance = pino(stream)\n  instance.level = 'info'\n  instance.info(null, 'a %s', 'string')\n\n  const result = await once(stream, 'data')\n  check(assert.equal, result, expected.level, expected.msg)\n})\n\ntest('fatal method sync-flushes the destination if sync flushing is available', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const stream = sink()\n  stream.flushSync = () => {\n    plan.ok('destination flushed')\n  }\n  const instance = pino(stream)\n  instance.fatal('this is fatal')\n  await once(stream, 'data')\n  plan.doesNotThrow(() => {\n    stream.flushSync = undefined\n    instance.fatal('this is fatal')\n  })\n\n  await plan\n})\n\ntest('fatal method should call async when sync-flushing fails', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const messages = [\n    'this is fatal 1'\n  ]\n  const stream = sink((result) => assert.equal(result.msg, messages.shift()))\n  stream.flushSync = () => { throw new Error('Error') }\n  stream.flush = () => { throw Error('flush should be called') }\n\n  const instance = pino(stream)\n  plan.doesNotThrow(() => instance.fatal(messages[0]))\n\n  await plan\n})\n\ntest('calling silent method on logger instance', async () => {\n  const instance = pino({ level: 'silent' }, sink((result, enc) => {\n    throw Error('no data should be logged')\n  }))\n  instance.silent('hello world')\n})\n\ntest('calling silent method on child logger', async () => {\n  const child = pino({ level: 'silent' }, sink((result, enc) => {\n    throw Error('no data should be logged')\n  })).child({})\n  child.silent('hello world')\n})\n\ntest('changing level from info to silent and back to info', async () => {\n  const expected = {\n    level: 30,\n    msg: 'hello world'\n  }\n  const stream = sink()\n  const instance = pino({ level: 'info' }, stream)\n\n  instance.level = 'silent'\n  instance.info('hello world')\n  let result = stream.read()\n  assert.equal(result, null)\n\n  instance.level = 'info'\n  instance.info('hello world')\n  result = await once(stream, 'data')\n  check(assert.equal, result, expected.level, expected.msg)\n})\n\ntest('changing level from info to silent and back to info in child logger', async () => {\n  const expected = {\n    level: 30,\n    msg: 'hello world'\n  }\n  const stream = sink()\n  const child = pino({ level: 'info' }, stream).child({})\n\n  child.level = 'silent'\n  child.info('hello world')\n  let result = stream.read()\n  assert.equal(result, null)\n\n  child.level = 'info'\n  child.info('hello world')\n  result = await once(stream, 'data')\n  check(assert.equal, result, expected.level, expected.msg)\n})\n\ndescribe('changing level respects level comparison set to', () => {\n  const ascLevels = {\n    debug: 1,\n    info: 2,\n    warn: 3\n  }\n\n  const descLevels = {\n    debug: 3,\n    info: 2,\n    warn: 1\n  }\n\n  const expected = {\n    level: 2,\n    msg: 'hello world'\n  }\n\n  test('ASC in parent logger', async () => {\n    const customLevels = ascLevels\n    const levelComparison = 'ASC'\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream)\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n\n  test('DESC in parent logger', async () => {\n    const customLevels = descLevels\n    const levelComparison = 'DESC'\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream)\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n\n  test('custom function in parent logger', async () => {\n    const customLevels = {\n      info: 2,\n      debug: 345,\n      warn: 789\n    }\n    const levelComparison = (current, expected) => {\n      if (expected === customLevels.warn) return false\n      return true\n    }\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream)\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n\n  test('ASC in child logger', async () => {\n    const customLevels = ascLevels\n    const levelComparison = 'ASC'\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ })\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n\n  test('DESC in parent logger', async () => {\n    const customLevels = descLevels\n    const levelComparison = 'DESC'\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ })\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n\n  test('custom function in child logger', async () => {\n    const customLevels = {\n      info: 2,\n      debug: 345,\n      warn: 789\n    }\n    const levelComparison = (current, expected) => {\n      if (expected === customLevels.warn) return false\n      return true\n    }\n\n    const stream = sink()\n    const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream).child({ })\n\n    logger.level = 'warn'\n    logger.info('hello world')\n    let result = stream.read()\n    assert.equal(result, null)\n\n    logger.level = 'debug'\n    logger.info('hello world')\n    result = await once(stream, 'data')\n    check(assert.equal, result, expected.level, expected.msg)\n  })\n})\n\ntest('changing level respects level comparison DESC', async () => {\n  const customLevels = {\n    warn: 1,\n    info: 2,\n    debug: 3\n  }\n\n  const levelComparison = 'DESC'\n\n  const expected = {\n    level: 2,\n    msg: 'hello world'\n  }\n\n  const stream = sink()\n  const logger = pino({ levelComparison, customLevels, useOnlyCustomLevels: true, level: 'info' }, stream)\n\n  logger.level = 'warn'\n  logger.info('hello world')\n  let result = stream.read()\n  assert.equal(result, null)\n\n  logger.level = 'debug'\n  logger.info('hello world')\n  result = await once(stream, 'data')\n  check(assert.equal, result, expected.level, expected.msg)\n})\n\n// testing for potential loss of Pino constructor scope from serializers - an edge case with circular refs see:  https://github.com/pinojs/pino/issues/833\ntest('trying to get levels when `this` is no longer a Pino instance returns an empty string', async () => {\n  const notPinoInstance = { some: 'object', getLevel: levelsLib.getLevel }\n  const blankedLevelValue = notPinoInstance.getLevel()\n  assert.equal(blankedLevelValue, '')\n})\n\ntest('accepts capital letter for INFO level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'INFO'\n  }, stream)\n\n  logger.info('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 30)\n})\n\ntest('accepts capital letter for FATAL level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'FATAL'\n  }, stream)\n\n  logger.fatal('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 60)\n})\n\ntest('accepts capital letter for ERROR level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'ERROR'\n  }, stream)\n\n  logger.error('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 50)\n})\n\ntest('accepts capital letter for WARN level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'WARN'\n  }, stream)\n\n  logger.warn('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 40)\n})\n\ntest('accepts capital letter for DEBUG level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'DEBUG'\n  }, stream)\n\n  logger.debug('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 20)\n})\n\ntest('accepts capital letter for TRACE level', async () => {\n  const stream = sink()\n  const logger = pino({\n    level: 'TRACE'\n  }, stream)\n\n  logger.trace('test')\n  const { level } = await once(stream, 'data')\n  assert.equal(level, 10)\n})\n"
  },
  {
    "path": "test/metadata.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst os = require('node:os')\nconst tspl = require('@matteo.collina/tspl')\n\nconst pino = require('../')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('metadata works', async (t) => {\n  const plan = tspl(t, { plan: 7 })\n  const now = Date.now()\n  const instance = pino({}, {\n    [Symbol.for('pino.metadata')]: true,\n    write (chunk) {\n      plan.equal(instance, this.lastLogger)\n      plan.equal(30, this.lastLevel)\n      plan.equal('a msg', this.lastMsg)\n      plan.ok(Number(this.lastTime) >= now)\n      plan.deepEqual(this.lastObj, { hello: 'world' })\n      const result = JSON.parse(chunk)\n      plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n      delete result.time\n      plan.deepEqual(result, {\n        pid,\n        hostname,\n        level: 30,\n        hello: 'world',\n        msg: 'a msg'\n      })\n    }\n  })\n\n  instance.info({ hello: 'world' }, 'a msg')\n\n  await plan\n})\n\ntest('child loggers works', async (t) => {\n  const plan = tspl(t, { plan: 6 })\n  const instance = pino({}, {\n    [Symbol.for('pino.metadata')]: true,\n    write (chunk) {\n      plan.equal(child, this.lastLogger)\n      plan.equal(30, this.lastLevel)\n      plan.equal('a msg', this.lastMsg)\n      plan.deepEqual(this.lastObj, { from: 'child' })\n      const result = JSON.parse(chunk)\n      plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n      delete result.time\n      plan.deepEqual(result, {\n        pid,\n        hostname,\n        level: 30,\n        hello: 'world',\n        from: 'child',\n        msg: 'a msg'\n      })\n    }\n  })\n\n  const child = instance.child({ hello: 'world' })\n  child.info({ from: 'child' }, 'a msg')\n\n  await plan\n})\n\ntest('without object', async (t) => {\n  const plan = tspl(t, { plan: 6 })\n  const instance = pino({}, {\n    [Symbol.for('pino.metadata')]: true,\n    write (chunk) {\n      plan.equal(instance, this.lastLogger)\n      plan.equal(30, this.lastLevel)\n      plan.equal('a msg', this.lastMsg)\n      plan.deepEqual({ }, this.lastObj)\n      const result = JSON.parse(chunk)\n      plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n      delete result.time\n      plan.deepEqual(result, {\n        pid,\n        hostname,\n        level: 30,\n        msg: 'a msg'\n      })\n    }\n  })\n\n  instance.info('a msg')\n\n  await plan\n})\n\ntest('without msg', async (t) => {\n  const plan = tspl(t, { plan: 6 })\n  const instance = pino({}, {\n    [Symbol.for('pino.metadata')]: true,\n    write (chunk) {\n      plan.equal(instance, this.lastLogger)\n      plan.equal(30, this.lastLevel)\n      plan.equal(undefined, this.lastMsg)\n      plan.deepEqual({ hello: 'world' }, this.lastObj)\n      const result = JSON.parse(chunk)\n      plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n      delete result.time\n      plan.deepEqual(result, {\n        pid,\n        hostname,\n        level: 30,\n        hello: 'world'\n      })\n    }\n  })\n\n  instance.info({ hello: 'world' })\n\n  await plan\n})\n"
  },
  {
    "path": "test/mixin-merge-strategy.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst level = 50\nconst name = 'error'\n\ntest('default merge strategy', async () => {\n  const stream = sink()\n  const instance = pino({\n    base: {},\n    mixin () {\n      return { tag: 'k8s' }\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({\n    tag: 'local'\n  }, 'test')\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    level,\n    msg: 'test',\n    tag: 'local'\n  })\n})\n\ntest('custom merge strategy with mixin priority', async () => {\n  const stream = sink()\n  const instance = pino({\n    base: {},\n    mixin () {\n      return { tag: 'k8s' }\n    },\n    mixinMergeStrategy (mergeObject, mixinObject) {\n      return Object.assign(mergeObject, mixinObject)\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({\n    tag: 'local'\n  }, 'test')\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    level,\n    msg: 'test',\n    tag: 'k8s'\n  })\n})\n"
  },
  {
    "path": "test/mixin.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst { pid } = process\nconst hostname = os.hostname()\nconst level = 50\nconst name = 'error'\n\ntest('mixin object is included', async () => {\n  let n = 0\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      return { hello: ++n }\n    }\n  }, stream)\n  instance.level = name\n  instance[name]('test')\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    msg: 'test',\n    hello: 1\n  })\n})\n\ntest('mixin object is new every time', async (t) => {\n  const plan = tspl(t, { plan: 6 })\n\n  let n = 0\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      return { hello: n }\n    }\n  }, stream)\n  instance.level = name\n\n  while (++n < 4) {\n    const msg = `test #${n}`\n    stream.pause()\n    instance[name](msg)\n    stream.resume()\n    const result = await once(stream, 'data')\n    plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n    delete result.time\n    plan.deepEqual(result, {\n      pid,\n      hostname,\n      level,\n      msg,\n      hello: n\n    })\n  }\n\n  await plan\n})\n\ntest('mixin object is not called if below log level', async () => {\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      throw Error('should not call mixin function')\n    }\n  }, stream)\n  instance.level = 'error'\n  instance.info('test')\n})\n\ntest('mixin object + logged object', async () => {\n  const stream = sink()\n  const instance = pino({\n    mixin () {\n      return { foo: 1, bar: 2 }\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({ bar: 3, baz: 4 })\n  const result = await once(stream, 'data')\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level,\n    foo: 1,\n    bar: 3,\n    baz: 4\n  })\n})\n\ntest('mixin not a function', async () => {\n  const stream = sink()\n  assert.throws(function () {\n    pino({ mixin: 'not a function' }, stream)\n  })\n})\n\ntest('mixin can use context', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  const instance = pino({\n    mixin (context) {\n      plan.ok(context !== null, 'context should be defined')\n      plan.ok(context !== undefined, 'context should be defined')\n      plan.deepEqual(context, {\n        message: '123',\n        stack: 'stack'\n      })\n      return Object.assign({\n        error: context.message,\n        stack: context.stack\n      })\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({\n    message: '123',\n    stack: 'stack'\n  }, 'test')\n\n  await plan\n})\n\ntest('mixin works without context', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  const instance = pino({\n    mixin (context) {\n      plan.ok(context !== null, 'context is still defined w/o passing mergeObject')\n      plan.ok(context !== undefined, 'context is still defined w/o passing mergeObject')\n      plan.deepEqual(context, {})\n      return {\n        something: true\n      }\n    }\n  }, stream)\n  instance.level = name\n  instance[name]('test')\n\n  await plan\n})\n\ntest('mixin can use level number', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  const instance = pino({\n    mixin (context, num) {\n      plan.ok(num !== null, 'level should be defined')\n      plan.ok(num !== undefined, 'level should be defined')\n      plan.deepEqual(num, level)\n      return Object.assign({\n        error: context.message,\n        stack: context.stack\n      })\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({\n    message: '123',\n    stack: 'stack'\n  }, 'test')\n\n  await plan\n})\n\ntest('mixin receives logger as third parameter', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  const instance = pino({\n    mixin (context, num, logger) {\n      plan.ok(logger !== null, 'logger should be defined')\n      plan.ok(logger !== undefined, 'logger should be defined')\n      plan.deepEqual(logger, instance)\n      return { ...context, num }\n    }\n  }, stream)\n  instance.level = name\n  instance[name]({\n    message: '123'\n  }, 'test')\n\n  await plan\n})\n\ntest('mixin receives child logger', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  let child = null\n  const instance = pino({\n    mixin (context, num, logger) {\n      plan.ok(logger !== null, 'logger should be defined')\n      plan.ok(logger !== undefined, 'logger should be defined')\n      plan.deepEqual(logger.expected, child.expected)\n      return { ...context, num }\n    }\n  }, stream)\n  instance.level = name\n  instance.expected = false\n  child = instance.child({})\n  child.expected = true\n  child[name]({\n    message: '123'\n  }, 'test')\n\n  await plan\n})\n\ntest('mixin receives logger even if child exists', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const stream = sink()\n  let child = null\n  const instance = pino({\n    mixin (context, num, logger) {\n      plan.ok(logger !== null, 'logger should be defined')\n      plan.ok(logger !== undefined, 'logger should be defined')\n      plan.deepEqual(logger.expected, instance.expected)\n      return { ...context, num }\n    }\n  }, stream)\n  instance.level = name\n  instance.expected = false\n  child = instance.child({})\n  child.expected = true\n  instance[name]({\n    message: '123'\n  }, 'test')\n\n  await plan\n})\n"
  },
  {
    "path": "test/multistream.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { readFileSync } = require('node:fs')\nconst { join } = require('node:path')\nconst proxyquire = require('proxyquire')\nconst strip = require('strip-ansi')\nconst tspl = require('@matteo.collina/tspl')\n\nconst writeStream = require('flush-write-stream')\nconst pino = require('../')\nconst multistream = pino.multistream\nconst { file, sink } = require('./helper')\n\ntest('sends to multiple streams using string levels', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'debug', stream },\n    { level: 'trace', stream },\n    { level: 'fatal', stream },\n    { level: 'silent', stream }\n  ]\n  const log = pino({\n    level: 'trace'\n  }, multistream(streams))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 9)\n})\n\ntest('sends to multiple streams using custom levels', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'debug', stream },\n    { level: 'trace', stream },\n    { level: 'fatal', stream },\n    { level: 'silent', stream }\n  ]\n  const log = pino({\n    level: 'trace'\n  }, multistream(streams))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 9)\n})\n\ntest('sends to multiple streams using optionally predefined levels', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const opts = {\n    levels: {\n      silent: Infinity,\n      fatal: 60,\n      error: 50,\n      warn: 50,\n      info: 30,\n      debug: 20,\n      trace: 10\n    }\n  }\n  const streams = [\n    { stream },\n    { level: 'trace', stream },\n    { level: 'debug', stream },\n    { level: 'info', stream },\n    { level: 'warn', stream },\n    { level: 'error', stream },\n    { level: 'fatal', stream },\n    { level: 'silent', stream }\n  ]\n  const mstream = multistream(streams, opts)\n  const log = pino({\n    level: 'trace'\n  }, mstream)\n  log.trace('trace stream')\n  log.debug('debug stream')\n  log.info('info stream')\n  log.warn('warn stream')\n  log.error('error stream')\n  log.fatal('fatal stream')\n  log.silent('silent stream')\n  assert.equal(messageCount, 24)\n})\n\ntest('sends to multiple streams using number levels', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 20, stream },\n    { level: 60, stream }\n  ]\n  const log = pino({\n    level: 'debug'\n  }, multistream(streams))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 6)\n})\n\ntest('level include higher levels', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const log = pino({}, multistream([{ level: 'info', stream }]))\n  log.fatal('message')\n  assert.equal(messageCount, 1)\n})\n\ntest('supports multiple arguments', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const messages = []\n  const stream = writeStream(function (data, enc, cb) {\n    messages.push(JSON.parse(data))\n    if (messages.length === 2) {\n      const msg1 = messages[0]\n      plan.equal(msg1.msg, 'foo bar baz foobar')\n\n      const msg2 = messages[1]\n      plan.equal(msg2.msg, 'foo bar baz foobar barfoo foofoo')\n    }\n    cb()\n  })\n  const log = pino({}, multistream({ stream }))\n  log.info('%s %s %s %s', 'foo', 'bar', 'baz', 'foobar') // apply not invoked\n  log.info('%s %s %s %s %s %s', 'foo', 'bar', 'baz', 'foobar', 'barfoo', 'foofoo') // apply invoked\n\n  await plan\n})\n\ntest('supports children', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const stream = writeStream(function (data, enc, cb) {\n    const input = JSON.parse(data)\n    plan.equal(input.msg, 'child stream')\n    plan.equal(input.child, 'one')\n    cb()\n  })\n  const streams = [\n    { stream }\n  ]\n  const log = pino({}, multistream(streams)).child({ child: 'one' })\n  log.info('child stream')\n\n  await plan\n})\n\ntest('supports grandchildren', async (t) => {\n  const plan = tspl(t, { plan: 9 })\n  const messages = []\n  const stream = writeStream(function (data, enc, cb) {\n    messages.push(JSON.parse(data))\n    if (messages.length === 3) {\n      const msg1 = messages[0]\n      plan.equal(msg1.msg, 'grandchild stream')\n      plan.equal(msg1.child, 'one')\n      plan.equal(msg1.grandchild, 'two')\n\n      const msg2 = messages[1]\n      plan.equal(msg2.msg, 'grandchild stream')\n      plan.equal(msg2.child, 'one')\n      plan.equal(msg2.grandchild, 'two')\n\n      const msg3 = messages[2]\n      plan.equal(msg3.msg, 'debug grandchild')\n      plan.equal(msg3.child, 'one')\n      plan.equal(msg3.grandchild, 'two')\n    }\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'debug', stream }\n  ]\n  const log = pino({\n    level: 'debug'\n  }, multistream(streams)).child({ child: 'one' }).child({ grandchild: 'two' })\n  log.info('grandchild stream')\n  log.debug('debug grandchild')\n\n  await plan\n})\n\ntest('supports custom levels', (t, end) => {\n  const stream = writeStream(function (data, enc, cb) {\n    assert.equal(JSON.parse(data).msg, 'bar')\n    end()\n  })\n  const log = pino({\n    customLevels: {\n      foo: 35\n    }\n  }, multistream([{ level: 35, stream }]))\n  log.foo('bar')\n})\n\ntest('supports pretty print', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const stream = writeStream(function (data, enc, cb) {\n    plan.equal(strip(data.toString()).match(/INFO.*: pretty print/) != null, true)\n    cb()\n  })\n\n  const safeBoom = proxyquire('pino-pretty/lib/utils/build-safe-sonic-boom.js', {\n    'sonic-boom': function () {\n      plan.ok('sonic created')\n      stream.flushSync = () => {}\n      stream.flush = () => {}\n      return stream\n    }\n  })\n  const nested = proxyquire('pino-pretty/lib/utils/index.js', {\n    './build-safe-sonic-boom.js': safeBoom\n  })\n  const pretty = proxyquire('pino-pretty', {\n    './lib/utils/index.js': nested\n  })\n\n  const log = pino({\n    level: 'debug',\n    name: 'helloName'\n  }, multistream([\n    { stream: pretty() }\n  ]))\n\n  log.info('pretty print')\n\n  await plan\n})\n\ntest('emit propagates events to each stream', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const handler = function (data) {\n    plan.equal(data.msg, 'world')\n  }\n  const streams = [sink(), sink(), sink()]\n  streams.forEach(function (s) {\n    s.once('hello', handler)\n  })\n  const stream = multistream(streams)\n  stream.emit('hello', { msg: 'world' })\n\n  await plan\n})\n\ntest('children support custom levels', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const stream = writeStream(function (data, enc, cb) {\n    plan.equal(JSON.parse(data).msg, 'bar')\n  })\n  const parent = pino({\n    customLevels: {\n      foo: 35\n    }\n  }, multistream([{ level: 35, stream }]))\n  const child = parent.child({ child: 'yes' })\n  child.foo('bar')\n\n  await plan\n})\n\ntest('levelVal overrides level', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'blabla', levelVal: 15, stream },\n    { level: 60, stream }\n  ]\n  const log = pino({\n    level: 'debug'\n  }, multistream(streams))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 6)\n})\n\ntest('forwards metadata', async (t) => {\n  const plan = tspl(t, { plan: 4 })\n  const streams = [\n    {\n      stream: {\n        [Symbol.for('pino.metadata')]: true,\n        write (chunk) {\n          plan.equal(log, this.lastLogger)\n          plan.equal(30, this.lastLevel)\n          plan.deepEqual({ hello: 'world' }, this.lastObj)\n          plan.deepEqual('a msg', this.lastMsg)\n        }\n      }\n    }\n  ]\n\n  const log = pino({\n    level: 'debug'\n  }, multistream(streams))\n\n  log.info({ hello: 'world' }, 'a msg')\n\n  await plan\n})\n\ntest('forward name', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const streams = [\n    {\n      stream: {\n        [Symbol.for('pino.metadata')]: true,\n        write (chunk) {\n          const line = JSON.parse(chunk)\n          plan.equal(line.name, 'helloName')\n          plan.equal(line.hello, 'world')\n        }\n      }\n    }\n  ]\n\n  const log = pino({\n    level: 'debug',\n    name: 'helloName'\n  }, multistream(streams))\n\n  log.info({ hello: 'world' }, 'a msg')\n\n  await plan\n})\n\ntest('forward name with child', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const streams = [\n    {\n      stream: {\n        write (chunk) {\n          const line = JSON.parse(chunk)\n          plan.equal(line.name, 'helloName')\n          plan.equal(line.hello, 'world')\n          plan.equal(line.component, 'aComponent')\n        }\n      }\n    }\n  ]\n\n  const log = pino({\n    level: 'debug',\n    name: 'helloName'\n  }, multistream(streams)).child({ component: 'aComponent' })\n\n  log.info({ hello: 'world' }, 'a msg')\n\n  await plan\n})\n\ntest('clone generates a new multistream with all stream at the same level', async (t) => {\n  const plan = tspl(t, { plan: 14 })\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'debug', stream },\n    { level: 'trace', stream },\n    { level: 'fatal', stream }\n  ]\n  const ms = multistream(streams)\n  const clone = ms.clone(30)\n\n  // eslint-disable-next-line eqeqeq\n  plan.equal(clone != ms, true)\n\n  clone.streams.forEach((s, i) => {\n    // eslint-disable-next-line eqeqeq\n    plan.equal(s != streams[i], true)\n    plan.equal(s.stream, streams[i].stream)\n    plan.equal(s.level, 30)\n  })\n\n  const log = pino({\n    level: 'trace'\n  }, clone)\n\n  log.info('info stream')\n  log.debug('debug message not counted')\n  log.fatal('fatal stream')\n  plan.equal(messageCount, 8)\n\n  await plan\n})\n\ntest('one stream', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const log = pino({\n    level: 'trace'\n  }, multistream({ stream, level: 'fatal' }))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 1)\n})\n\ntest('dedupe', async () => {\n  let messageCount = 0\n  const stream1 = writeStream(function (data, enc, cb) {\n    messageCount -= 1\n    cb()\n  })\n\n  const stream2 = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n\n  const streams = [\n    {\n      stream: stream1,\n      level: 'info'\n    },\n    {\n      stream: stream2,\n      level: 'fatal'\n    }\n  ]\n\n  const log = pino({\n    level: 'trace'\n  }, multistream(streams, { dedupe: true }))\n  log.info('info stream')\n  log.fatal('fatal stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 1)\n})\n\ntest('dedupe when logs have different levels', async () => {\n  let messageCount = 0\n  const stream1 = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n\n  const stream2 = writeStream(function (data, enc, cb) {\n    messageCount += 2\n    cb()\n  })\n\n  const streams = [\n    {\n      stream: stream1,\n      level: 'info'\n    },\n    {\n      stream: stream2,\n      level: 'error'\n    }\n  ]\n\n  const log = pino({\n    level: 'trace'\n  }, multistream(streams, { dedupe: true }))\n\n  log.info('info stream')\n  log.warn('warn stream')\n  log.error('error streams')\n  log.fatal('fatal streams')\n  assert.equal(messageCount, 6)\n})\n\ntest('dedupe when some streams has the same level', async () => {\n  let messageCount = 0\n  const stream1 = writeStream(function (data, enc, cb) {\n    messageCount -= 1\n    cb()\n  })\n\n  const stream2 = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n\n  const stream3 = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n\n  const streams = [\n    {\n      stream: stream1,\n      level: 'info'\n    },\n    {\n      stream: stream2,\n      level: 'fatal'\n    },\n    {\n      stream: stream3,\n      level: 'fatal'\n    }\n  ]\n\n  const log = pino({\n    level: 'trace'\n  }, multistream(streams, { dedupe: true }))\n  log.info('info stream')\n  log.fatal('fatal streams')\n  log.fatal('fatal streams')\n  assert.equal(messageCount, 3)\n})\n\ntest('no stream', async () => {\n  const log = pino({\n    level: 'trace'\n  }, multistream())\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n})\n\ntest('one stream', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const log = pino({\n    level: 'trace'\n  }, multistream(stream))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 2)\n})\n\ntest('add a stream', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n\n  const log = pino({\n    level: 'trace'\n  }, multistream().add(stream))\n  log.info('info stream')\n  log.debug('debug stream')\n  log.fatal('fatal stream')\n  assert.equal(messageCount, 2)\n})\n\ntest('remove a stream', async () => {\n  let messageCount1 = 0\n  let messageCount2 = 0\n  let messageCount3 = 0\n\n  const stream1 = writeStream(function (data, enc, cb) {\n    messageCount1 += 1\n    cb()\n  })\n\n  const stream2 = writeStream(function (data, enc, cb) {\n    messageCount2 += 1\n    cb()\n  })\n\n  const stream3 = writeStream(function (data, enc, cb) {\n    messageCount3 += 1\n    cb()\n  })\n\n  const multi = multistream()\n  const log = pino({ level: 'trace', sync: true }, multi)\n\n  multi.add(stream1)\n  const id1 = multi.lastId\n\n  multi.add(stream2)\n  const id2 = multi.lastId\n\n  multi.add(stream3)\n  const id3 = multi.lastId\n\n  log.info('line')\n  multi.remove(id1)\n\n  log.info('line')\n  multi.remove(id2)\n\n  log.info('line')\n  multi.remove(id3)\n\n  log.info('line')\n  multi.remove(Math.floor(Math.random() * 1000)) // non-existing id\n\n  assert.equal(messageCount1, 1)\n  assert.equal(messageCount2, 2)\n  assert.equal(messageCount3, 3)\n})\n\ntest('multistream.add throws if not a stream', async () => {\n  try {\n    pino({\n      level: 'trace'\n    }, multistream().add({}))\n  } catch (_) {\n  }\n})\n\ntest('multistream throws if not a stream', async () => {\n  try {\n    pino({\n      level: 'trace'\n    }, multistream({}))\n  } catch (_) {\n  }\n})\n\ntest('multistream.write should not throw if one stream fails', async () => {\n  let messageCount = 0\n  const stream = writeStream(function (data, enc, cb) {\n    messageCount += 1\n    cb()\n  })\n  const noopStream = pino.transport({\n    target: join(__dirname, 'fixtures', 'noop-transport.js')\n  })\n  // eslint-disable-next-line\n  noopStream.on('error', function (err) {\n    // something went wrong while writing to noop stream, ignoring!\n  })\n  const log = pino({\n    level: 'trace'\n  },\n  multistream([\n    {\n      level: 'trace',\n      stream\n    },\n    {\n      level: 'debug',\n      stream: noopStream\n    }\n  ])\n  )\n  log.debug('0')\n  noopStream.end()\n  // noop stream is ending, should emit an error but not throw\n  log.debug('1')\n  log.debug('2')\n  assert.equal(messageCount, 3)\n})\n\ntest('flushSync', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const tmp = file()\n  const destination = pino.destination({ dest: tmp, sync: false, minLength: 4096 })\n  const stream = multistream([{ level: 'info', stream: destination }])\n  const log = pino({ level: 'info' }, stream)\n  destination.on('ready', () => {\n    log.info('foo')\n    log.info('bar')\n    stream.flushSync()\n    plan.equal(readFileSync(tmp, { encoding: 'utf-8' }).split('\\n').length - 1, 2)\n    log.info('biz')\n    stream.flushSync()\n    plan.equal(readFileSync(tmp, { encoding: 'utf-8' }).split('\\n').length - 1, 3)\n  })\n\n  await plan\n})\n\ntest('ends all streams', async (t) => {\n  const plan = tspl(t, { plan: 7 })\n  const stream = writeStream(function (data, enc, cb) {\n    plan.ok('message')\n    cb()\n  })\n  stream.flushSync = function () {\n    plan.ok('flushSync')\n  }\n  // stream2 has no flushSync\n  const stream2 = writeStream(function (data, enc, cb) {\n    plan.ok('message2')\n    cb()\n  })\n  const streams = [\n    { stream },\n    { level: 'debug', stream },\n    { level: 'trace', stream: stream2 },\n    { level: 'fatal', stream },\n    { level: 'silent', stream }\n  ]\n  const multi = multistream(streams)\n  const log = pino({\n    level: 'trace'\n  }, multi)\n  log.info('info stream')\n  multi.end()\n\n  await plan\n})\n"
  },
  {
    "path": "test/redact.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\ntest('redact option – throws if not array', async () => {\n  assert.throws(() => {\n    pino({ redact: 'req.headers.cookie' })\n  })\n})\n\ntest('redact option – throws if array does not only contain strings', async () => {\n  assert.throws(() => {\n    pino({ redact: ['req.headers.cookie', {}] })\n  })\n})\n\ntest('redact option – throws if array contains an invalid path', async () => {\n  assert.throws(() => {\n    pino({ redact: ['req,headers.cookie'] })\n  })\n})\n\ntest('redact.paths option – throws if not array', async () => {\n  assert.throws(() => {\n    pino({ redact: { paths: 'req.headers.cookie' } })\n  })\n})\n\ntest('redact.paths option – throws if array does not only contain strings', async () => {\n  assert.throws(() => {\n    pino({ redact: { paths: ['req.headers.cookie', {}] } })\n  })\n})\n\ntest('redact.paths option – throws if array contains an invalid path', async () => {\n  assert.throws(() => {\n    pino({ redact: { paths: ['req,headers.cookie'] } })\n  })\n})\n\ntest('redact option – top level key', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['key'] }, stream)\n  instance.info({\n    key: { redact: 'me' }\n  })\n  const { key } = await once(stream, 'data')\n  assert.equal(key, '[Redacted]')\n})\n\ntest('redact option – top level key next level key', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['key', 'key.foo'] }, stream)\n  instance.info({\n    key: { redact: 'me' }\n  })\n  const { key } = await once(stream, 'data')\n  assert.equal(key, '[Redacted]')\n})\n\ntest('redact option – next level key then top level key', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['key.foo', 'key'] }, stream)\n  instance.info({\n    key: { redact: 'me' }\n  })\n  const { key } = await once(stream, 'data')\n  assert.equal(key, '[Redacted]')\n})\n\ntest('redact option – object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.headers.cookie'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redact option – child object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.headers.cookie'] }, stream)\n  instance.child({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redact option – interpolated object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.headers.cookie'] }, stream)\n\n  instance.info('test %j', {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { msg } = await once(stream, 'data')\n  assert.equal(JSON.parse(msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')\n})\n\ntest('redact.paths option – object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'] } }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redact.paths option – child object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'] } }, stream)\n  instance.child({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redact.paths option – interpolated object', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'] } }, stream)\n\n  instance.info('test %j', {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { msg } = await once(stream, 'data')\n  assert.equal(JSON.parse(msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')\n})\n\ntest('redact.censor option – sets the redact value', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'], censor: 'test' } }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, 'test')\n})\n\ntest('redact.censor option – can be a function that accepts value and path arguments', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['topLevel'], censor: (value, path) => value + ' ' + path.join('.') } }, stream)\n  instance.info({\n    topLevel: 'test'\n  })\n  const { topLevel } = await once(stream, 'data')\n  assert.equal(topLevel, 'test topLevel')\n})\n\ntest('redact.censor option – can be a function that accepts value and path arguments (nested path)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'], censor: (value, path) => value + ' ' + path.join('.') } }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1; req.headers.cookie')\n})\n\ntest('redact.remove option – removes both key and value', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'], remove: true } }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal('cookie' in req.headers, false)\n})\n\ntest('redact.remove – top level key - object value', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['key'], remove: true } }, stream)\n  instance.info({\n    key: { redact: 'me' }\n  })\n  const o = await once(stream, 'data')\n  assert.equal('key' in o, false)\n})\n\ntest('redact.remove – top level key - number value', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['key'], remove: true } }, stream)\n  instance.info({\n    key: 1\n  })\n  const o = await once(stream, 'data')\n  assert.equal('key' in o, false)\n})\n\ntest('redact.remove – top level key - boolean value', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['key'], remove: true } }, stream)\n  instance.info({\n    key: false\n  })\n  const o = await once(stream, 'data')\n  assert.equal('key' in o, false)\n})\n\ntest('redact.remove – top level key in child logger', async () => {\n  const stream = sink()\n  const opts = { redact: { paths: ['key'], remove: true } }\n  const instance = pino(opts, stream).child({ key: { redact: 'me' } })\n  instance.info('test')\n  const o = await once(stream, 'data')\n  assert.equal('key' in o, false)\n})\n\ntest('redact.paths preserves original object values after the log write', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.headers.cookie'] }, stream)\n  const obj = {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.req.headers.cookie, '[Redacted]')\n  assert.equal(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')\n})\n\ntest('redact.paths preserves original object values after the log write', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'] } }, stream)\n  const obj = {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.req.headers.cookie, '[Redacted]')\n  assert.equal(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')\n})\n\ntest('redact.censor preserves original object values after the log write', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'], censor: 'test' } }, stream)\n  const obj = {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.req.headers.cookie, 'test')\n  assert.equal(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')\n})\n\ntest('redact.remove preserves original object values after the log write', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['req.headers.cookie'], remove: true } }, stream)\n  const obj = {\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal('cookie' in o.req.headers, false)\n  assert.equal('cookie' in obj.req.headers, true)\n})\n\ntest('redact – supports last position wildcard paths', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.headers.*'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n  assert.equal(req.headers.host, '[Redacted]')\n  assert.equal(req.headers.connection, '[Redacted]')\n})\n\ntest('redact – supports first position wildcard paths', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['*.headers'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers, '[Redacted]')\n})\n\ntest('redact – supports first position wildcards before other paths', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['*.headers.cookie', 'req.id'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n  assert.equal(req.id, '[Redacted]')\n})\n\ntest('redact – supports first position wildcards after other paths', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.id', '*.headers.cookie'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n  assert.equal(req.id, '[Redacted]')\n})\n\ntest('redact – supports first position wildcards after top level keys', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['key', '*.headers.cookie'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redact – supports top level wildcard', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['*'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req, '[Redacted]')\n})\n\ntest('redact – supports top level wildcard with a censor function', async () => {\n  const stream = sink()\n  const instance = pino({\n    redact: {\n      paths: ['*'],\n      censor: () => '[Redacted]'\n    }\n  }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req, '[Redacted]')\n})\n\ntest('redact – supports top level wildcard and leading wildcard', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['*', '*.req'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req, '[Redacted]')\n})\n\ntest('redact – supports intermediate wildcard paths', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.*.cookie'] }, stream)\n  instance.info({\n    req: {\n      id: 7915,\n      method: 'GET',\n      url: '/',\n      headers: {\n        host: 'localhost:3000',\n        connection: 'keep-alive',\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      },\n      remoteAddress: '::ffff:127.0.0.1',\n      remotePort: 58022\n    }\n  })\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('redacts numbers at the top level', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['id'] }, stream)\n  const obj = {\n    id: 7915\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.id, '[Redacted]')\n})\n\ntest('redacts booleans at the top level', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['maybe'] }, stream)\n  const obj = {\n    maybe: true\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.maybe, '[Redacted]')\n})\n\ntest('redacts strings at the top level', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['s'] }, stream)\n  const obj = {\n    s: 's'\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.s, '[Redacted]')\n})\n\ntest('does not redact primitives if not objects', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['a.b'] }, stream)\n  const obj = {\n    a: 42\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.a, 42)\n})\n\ntest('redacts null at the top level', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['n'] }, stream)\n  const obj = {\n    n: null\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.n, '[Redacted]')\n})\n\ntest('supports bracket notation', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['a[\"b.b\"]'] }, stream)\n  const obj = {\n    a: { 'b.b': 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.a['b.b'], '[Redacted]')\n})\n\ntest('supports bracket notation with further nesting', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['a[\"b.b\"].c'] }, stream)\n  const obj = {\n    a: { 'b.b': { c: 'd' } }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.a['b.b'].c, '[Redacted]')\n})\n\ntest('supports bracket notation with empty string as path segment', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['a[\"\"].c'] }, stream)\n  const obj = {\n    a: { '': { c: 'd' } }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o.a[''].c, '[Redacted]')\n})\n\ntest('supports leading bracket notation (single quote)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['[\\'a.a\\'].b'] }, stream)\n  const obj = {\n    'a.a': { b: 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o['a.a'].b, '[Redacted]')\n})\n\ntest('supports leading bracket notation (double quote)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['[\"a.a\"].b'] }, stream)\n  const obj = {\n    'a.a': { b: 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o['a.a'].b, '[Redacted]')\n})\n\ntest('supports leading bracket notation (backtick quote)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['[`a.a`].b'] }, stream)\n  const obj = {\n    'a.a': { b: 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o['a.a'].b, '[Redacted]')\n})\n\ntest('supports leading bracket notation (single-segment path)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['[`a.a`]'] }, stream)\n  const obj = {\n    'a.a': { b: 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o['a.a'], '[Redacted]')\n})\n\ntest('supports leading bracket notation (single-segment path, wildcard)', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['[*]'] }, stream)\n  const obj = {\n    'a.a': { b: 'c' }\n  }\n  instance.info(obj)\n  const o = await once(stream, 'data')\n  assert.equal(o['a.a'], '[Redacted]')\n})\n\ntest('child bindings are redacted using wildcard path', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['*.headers.cookie'] }, stream)\n  instance.child({\n    req: {\n      method: 'GET',\n      url: '/',\n      headers: {\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      }\n    }\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n})\n\ntest('child bindings are redacted using wildcard and plain path keys', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.method', '*.headers.cookie'] }, stream)\n  instance.child({\n    req: {\n      method: 'GET',\n      url: '/',\n      headers: {\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      }\n    }\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, '[Redacted]')\n  assert.equal(req.method, '[Redacted]')\n})\n\ntest('redacts boolean at the top level', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['msg'] }, stream)\n  const obj = {\n    s: 's'\n  }\n  instance.info(obj, true)\n  const o = await once(stream, 'data')\n  assert.equal(o.s, 's')\n  assert.equal(o.msg, '[Redacted]')\n})\n\ntest('child can customize redact', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.method', '*.headers.cookie'] }, stream)\n  instance.child({\n    req: {\n      method: 'GET',\n      url: '/',\n      headers: {\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      }\n    }\n  }, {\n    redact: ['req.url']\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')\n  assert.equal(req.method, 'GET')\n  assert.equal(req.url, '[Redacted]')\n})\n\ntest('child can remove parent redact by array', async () => {\n  const stream = sink()\n  const instance = pino({ redact: ['req.method', '*.headers.cookie'] }, stream)\n  instance.child({\n    req: {\n      method: 'GET',\n      url: '/',\n      headers: {\n        cookie: 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;'\n      }\n    }\n  }, {\n    redact: []\n  }).info('message completed')\n  const { req } = await once(stream, 'data')\n  assert.equal(req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')\n  assert.equal(req.method, 'GET')\n})\n\ntest('redact safe stringify', async () => {\n  const stream = sink()\n  const instance = pino({ redact: { paths: ['that.secret'] } }, stream)\n\n  instance.info({\n    that: {\n      secret: 'please hide me',\n      myBigInt: 123n\n    },\n    other: {\n      mySecondBigInt: 222n\n    }\n  })\n  const { that, other } = await once(stream, 'data')\n  assert.equal(that.secret, '[Redacted]')\n  assert.equal(that.myBigInt, 123)\n  assert.equal(other.mySecondBigInt, 222)\n})\n\ntest('censor function should not be called for non-existent nested paths (issue #2313)', async () => {\n  const stream = sink()\n  const censorCalls = []\n\n  const instance = pino({\n    redact: {\n      paths: ['a.b.c', 'req.authorization', 'url'],\n      censor (value, path) {\n        censorCalls.push({ value, path: path.join('.') })\n        if (typeof value !== 'string') {\n          return '***'\n        }\n        return '***'\n      }\n    }\n  }, stream)\n\n  // Test case 1: parent exists but nested path doesn't\n  censorCalls.length = 0\n  instance.info({ req: { id: 'test' } }, 'test message')\n  await once(stream, 'data')\n  assert.equal(censorCalls.length, 0, 'censor should not be called when req.authorization does not exist')\n\n  // Test case 2: parent exists but deeply nested path doesn't\n  censorCalls.length = 0\n  instance.info({ a: { d: 'test' } }, 'test message')\n  await once(stream, 'data')\n  assert.equal(censorCalls.length, 0, 'censor should not be called when a.b.c does not exist')\n\n  // Test case 3: multiple parent keys exist but nested paths don't\n  censorCalls.length = 0\n  instance.info({ a: { c: 'should-not-show-me' }, req: { id: 'test' } }, 'test message')\n  await once(stream, 'data')\n  assert.equal(censorCalls.length, 0, 'censor should not be called when neither a.b.c nor req.authorization exist')\n\n  // Test case 4: verify censor IS called when path exists\n  censorCalls.length = 0\n  instance.info({ req: { authorization: 'bearer token' } }, 'test message')\n  await once(stream, 'data')\n  assert.equal(censorCalls.length, 1, 'censor should be called when req.authorization exists')\n  assert.equal(censorCalls[0].path, 'req.authorization')\n  assert.equal(censorCalls[0].value, 'bearer token')\n})\n"
  },
  {
    "path": "test/serializers.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst stdSerializers = require('pino-std-serializers')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\nconst parentSerializers = {\n  test: () => 'parent'\n}\n\nconst childSerializers = {\n  test: () => 'child'\n}\n\ntest('default err namespace error serializer', async () => {\n  const stream = sink()\n  const parent = pino(stream)\n\n  parent.info({ err: ReferenceError('test') })\n  const o = await once(stream, 'data')\n  assert.equal(typeof o.err, 'object')\n  assert.equal(o.err.type, 'ReferenceError')\n  assert.equal(o.err.message, 'test')\n  assert.equal(typeof o.err.stack, 'string')\n})\n\ntest('custom serializer overrides default err namespace error serializer', async () => {\n  const stream = sink()\n  const parent = pino({\n    serializers: {\n      err: (e) => ({\n        t: e.constructor.name,\n        m: e.message,\n        s: e.stack\n      })\n    }\n  }, stream)\n\n  parent.info({ err: ReferenceError('test') })\n  const o = await once(stream, 'data')\n  assert.equal(typeof o.err, 'object')\n  assert.equal(o.err.t, 'ReferenceError')\n  assert.equal(o.err.m, 'test')\n  assert.equal(typeof o.err.s, 'string')\n})\n\ntest('custom serializer overrides default err namespace error serializer when nestedKey is on', async () => {\n  const stream = sink()\n  const parent = pino({\n    nestedKey: 'obj',\n    serializers: {\n      err: (e) => {\n        return {\n          t: e.constructor.name,\n          m: e.message,\n          s: e.stack\n        }\n      }\n    }\n  }, stream)\n\n  parent.info({ err: ReferenceError('test') })\n  const o = await once(stream, 'data')\n  assert.equal(typeof o.obj.err, 'object')\n  assert.equal(o.obj.err.t, 'ReferenceError')\n  assert.equal(o.obj.err.m, 'test')\n  assert.equal(typeof o.obj.err.s, 'string')\n})\n\ntest('null overrides default err namespace error serializer', async () => {\n  const stream = sink()\n  const parent = pino({ serializers: { err: null } }, stream)\n\n  parent.info({ err: ReferenceError('test') })\n  const o = await once(stream, 'data')\n  assert.equal(typeof o.err, 'object')\n  assert.equal(typeof o.err.type, 'undefined')\n  assert.equal(typeof o.err.message, 'undefined')\n  assert.equal(typeof o.err.stack, 'undefined')\n})\n\ntest('undefined overrides default err namespace error serializer', async () => {\n  const stream = sink()\n  const parent = pino({ serializers: { err: undefined } }, stream)\n\n  parent.info({ err: ReferenceError('test') })\n  const o = await once(stream, 'data')\n  assert.equal(typeof o.err, 'object')\n  assert.equal(typeof o.err.type, 'undefined')\n  assert.equal(typeof o.err.message, 'undefined')\n  assert.equal(typeof o.err.stack, 'undefined')\n})\n\ntest('serializers override values', async () => {\n  const stream = sink()\n  const parent = pino({ serializers: parentSerializers }, stream)\n  parent.child({}, { serializers: childSerializers })\n\n  parent.fatal({ test: 'test' })\n  const o = await once(stream, 'data')\n  assert.equal(o.test, 'parent')\n})\n\ntest('child does not overwrite parent serializers', async () => {\n  const stream = sink()\n  const parent = pino({ serializers: parentSerializers }, stream)\n  const child = parent.child({}, { serializers: childSerializers })\n\n  parent.fatal({ test: 'test' })\n\n  const o = once(stream, 'data')\n  assert.equal((await o).test, 'parent')\n  const o2 = once(stream, 'data')\n  child.fatal({ test: 'test' })\n  assert.equal((await o2).test, 'child')\n})\n\ntest('Symbol.for(\\'pino.serializers\\')', async () => {\n  const stream = sink()\n  const expected = Object.assign({\n    err: stdSerializers.err\n  }, parentSerializers)\n  const parent = pino({ serializers: parentSerializers }, stream)\n  const child = parent.child({ a: 'property' })\n\n  assert.deepEqual(parent[Symbol.for('pino.serializers')], expected)\n  assert.deepEqual(child[Symbol.for('pino.serializers')], expected)\n  assert.equal(parent[Symbol.for('pino.serializers')], child[Symbol.for('pino.serializers')])\n\n  const child2 = parent.child({}, {\n    serializers: {\n      a\n    }\n  })\n\n  function a () {\n    return 'hello'\n  }\n\n  // eslint-disable-next-line eqeqeq\n  assert.equal(child2[Symbol.for('pino.serializers')] != parentSerializers, true)\n  assert.equal(child2[Symbol.for('pino.serializers')].a, a)\n  assert.equal(child2[Symbol.for('pino.serializers')].test, parentSerializers.test)\n})\n\ntest('children inherit parent serializers', async () => {\n  const stream = sink()\n  const parent = pino({ serializers: parentSerializers }, stream)\n\n  const child = parent.child({ a: 'property' })\n  child.fatal({ test: 'test' })\n  const o = await once(stream, 'data')\n  assert.equal(o.test, 'parent')\n})\n\ntest('children inherit parent Symbol serializers', async () => {\n  const stream = sink()\n  const symbolSerializers = {\n    [Symbol.for('b')]: b\n  }\n  const expected = Object.assign({\n    err: stdSerializers.err\n  }, symbolSerializers)\n  const parent = pino({ serializers: symbolSerializers }, stream)\n\n  assert.deepEqual(parent[Symbol.for('pino.serializers')], expected)\n\n  const child = parent.child({}, {\n    serializers: {\n      [Symbol.for('a')]: a,\n      a\n    }\n  })\n\n  function a () {\n    return 'hello'\n  }\n\n  function b () {\n    return 'world'\n  }\n\n  assert.deepEqual(child[Symbol.for('pino.serializers')].a, a)\n  assert.deepEqual(child[Symbol.for('pino.serializers')][Symbol.for('b')], b)\n  assert.deepEqual(child[Symbol.for('pino.serializers')][Symbol.for('a')], a)\n})\n\ntest('children serializers get called', async () => {\n  const stream = sink()\n  const parent = pino({\n    test: 'this'\n  }, stream)\n\n  const child = parent.child({ a: 'property' }, { serializers: childSerializers })\n\n  child.fatal({ test: 'test' })\n  const o = await once(stream, 'data')\n  assert.equal(o.test, 'child')\n})\n\ntest('children serializers get called when inherited from parent', async () => {\n  const stream = sink()\n  const parent = pino({\n    test: 'this',\n    serializers: parentSerializers\n  }, stream)\n\n  const child = parent.child({}, { serializers: { test: function () { return 'pass' } } })\n\n  child.fatal({ test: 'fail' })\n  const o = await once(stream, 'data')\n  assert.equal(o.test, 'pass')\n})\n\ntest('non-overridden serializers are available in the children', async () => {\n  const stream = sink()\n  const pSerializers = {\n    onlyParent: function () { return 'parent' },\n    shared: function () { return 'parent' }\n  }\n\n  const cSerializers = {\n    shared: function () { return 'child' },\n    onlyChild: function () { return 'child' }\n  }\n\n  const parent = pino({ serializers: pSerializers }, stream)\n\n  const child = parent.child({}, { serializers: cSerializers })\n\n  const o = once(stream, 'data')\n  child.fatal({ shared: 'test' })\n  assert.equal((await o).shared, 'child')\n  const o2 = once(stream, 'data')\n  child.fatal({ onlyParent: 'test' })\n  assert.equal((await o2).onlyParent, 'parent')\n  const o3 = once(stream, 'data')\n  child.fatal({ onlyChild: 'test' })\n  assert.equal((await o3).onlyChild, 'child')\n  const o4 = once(stream, 'data')\n  parent.fatal({ onlyChild: 'test' })\n  assert.equal((await o4).onlyChild, 'test')\n})\n\ntest('custom serializer for messageKey', async () => {\n  const stream = sink()\n  const instance = pino({ serializers: { msg: () => '422' } }, stream)\n\n  const o = { num: NaN }\n  instance.info(o, 42)\n\n  const { msg } = await once(stream, 'data')\n  assert.equal(msg, '422')\n})\n"
  },
  {
    "path": "test/stdout-protection.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { fork } = require('node:child_process')\nconst writer = require('flush-write-stream')\n\nconst { once } = require('./helper')\nconst pino = require('..')\n\ntest('do not use SonicBoom is someone tampered with process.stdout.write', async () => {\n  let actual = ''\n  const child = fork(join(__dirname, 'fixtures', 'stdout-hack-protection.js'), { silent: true })\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n  await once(child, 'close')\n  assert.equal(actual.match(/^hack/) != null, true)\n})\n\ntest('do not use SonicBoom is someone has passed process.stdout to pino', async () => {\n  const logger = pino(process.stdout)\n  assert.equal(logger[pino.symbols.streamSym], process.stdout)\n})\n\ntest('do not crash if process.stdout has no fd', async (t) => {\n  const fd = process.stdout.fd\n  delete process.stdout.fd\n  t.after(function () { process.stdout.fd = fd })\n  pino()\n})\n\ntest('use fd=1 if process.stdout has no fd in pino.destination() (worker case)', async (t) => {\n  const fd = process.stdout.fd\n  delete process.stdout.fd\n  t.after(function () { process.stdout.fd = fd })\n  pino.destination()\n})\n"
  },
  {
    "path": "test/syncfalse.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { promises: { readFile }, createWriteStream } = require('node:fs')\nconst { join } = require('node:path')\nconst { fork } = require('node:child_process')\nconst writer = require('flush-write-stream')\nconst {\n  once,\n  getPathToNull,\n  file,\n  watchFileCreated\n} = require('./helper')\nconst { promisify } = require('node:util')\nconst tspl = require('@matteo.collina/tspl')\n\nconst sleep = promisify(setTimeout)\n\ntest('asynchronous logging', async (t) => {\n  const now = Date.now\n  const hostname = os.hostname\n  const proc = process\n  global.process = {\n    __proto__: process,\n    pid: 123456\n  }\n  Date.now = () => 1459875739796\n  os.hostname = () => 'abcdefghijklmnopqr'\n  delete require.cache[require.resolve('../')]\n  const pino = require('../')\n  let expected = ''\n  let actual = ''\n  const normal = pino(writer((s, enc, cb) => {\n    expected += s\n    cb()\n  }))\n\n  const dest = createWriteStream(getPathToNull())\n  dest.write = (s) => {\n    actual += s\n  }\n  const asyncLogger = pino(dest)\n\n  let i = 44\n  while (i--) {\n    normal.info('h')\n    asyncLogger.info('h')\n  }\n\n  const expected2 = expected.split('\\n')[0]\n  let actual2 = ''\n\n  const child = fork(join(__dirname, '/fixtures/syncfalse.js'), { silent: true })\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual2 += s\n    cb()\n  }))\n  await once(child, 'close')\n  // Wait for the last write to be flushed\n  await sleep(100)\n  assert.equal(actual, expected)\n  assert.equal(actual2.trim(), expected2)\n\n  t.after(() => {\n    os.hostname = hostname\n    Date.now = now\n    global.process = proc\n  })\n})\n\ntest('sync false with child', async (t) => {\n  const now = Date.now\n  const hostname = os.hostname\n  const proc = process\n  global.process = {\n    __proto__: process,\n    pid: 123456\n  }\n  Date.now = function () {\n    return 1459875739796\n  }\n  os.hostname = function () {\n    return 'abcdefghijklmnopqr'\n  }\n  delete require.cache[require.resolve('../')]\n  const pino = require('../')\n  let expected = ''\n  let actual = ''\n  const normal = pino(writer((s, enc, cb) => {\n    expected += s\n    cb()\n  })).child({ hello: 'world' })\n\n  const dest = createWriteStream(getPathToNull())\n  dest.write = function (s) {\n    actual += s\n  }\n  const asyncLogger = pino(dest).child({ hello: 'world' })\n\n  let i = 500\n  while (i--) {\n    normal.info('h')\n    asyncLogger.info('h')\n  }\n\n  asyncLogger.flush()\n\n  const expected2 = expected.split('\\n')[0]\n  let actual2 = ''\n\n  const child = fork(join(__dirname, '/fixtures/syncfalse-child.js'), { silent: true })\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual2 += s\n    cb()\n  }))\n  await once(child, 'close')\n  assert.equal(actual, expected)\n  assert.equal(actual2.trim(), expected2)\n\n  t.after(() => {\n    os.hostname = hostname\n    Date.now = now\n    global.process = proc\n  })\n})\n\ntest('flush does nothing with sync true (default)', async () => {\n  const instance = require('..')()\n  assert.equal(instance.flush(), undefined)\n})\n\ntest('should still call flush callback even when does nothing with sync true (default)', async (t) => {\n  const plan = tspl(t, { plan: 3 })\n  const instance = require('..')()\n  instance.flush((...args) => {\n    plan.ok('flush called')\n    plan.deepEqual(args, [])\n\n    // next tick to make flush not called more than once\n    process.nextTick(() => {\n      plan.ok('flush next tick called')\n    })\n  })\n\n  await plan\n})\n\ntest('should call the flush callback when flushed the data for async logger', async () => {\n  const outputPath = file()\n  async function getOutputLogLines () {\n    return (await readFile(outputPath)).toString().trim().split('\\n').map(JSON.parse)\n  }\n\n  const pino = require('../')\n\n  const instance = pino({}, pino.destination({\n    dest: outputPath,\n\n    // to make sure it does not flush on its own\n    minLength: 4096\n  }))\n  const flushPromise = promisify(instance.flush).bind(instance)\n\n  instance.info('hello')\n  await flushPromise()\n  await watchFileCreated(outputPath)\n\n  const [firstFlushData] = await getOutputLogLines()\n\n  assert.equal(firstFlushData.msg, 'hello')\n\n  // should not flush this as no data accumulated that's bigger than min length\n  instance.info('world')\n\n  // Making sure data is not flushed yet\n  const afterLogData = await getOutputLogLines()\n  assert.equal(afterLogData.length, 1)\n\n  await flushPromise()\n\n  // Making sure data is not flushed yet\n  const afterSecondFlush = (await getOutputLogLines())[1]\n  assert.equal(afterSecondFlush.msg, 'world')\n})\n"
  },
  {
    "path": "test/timestamp-nano.test.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\n\ntest('pino.stdTimeFunctions.isoTimeNano returns RFC 3339 timestamps', async () => {\n  // Mock Date.now at module initialization time\n  const now = Date.now\n  Date.now = () => new Date('2025-08-01T15:03:45.000000000Z').getTime()\n\n  // Mock process.hrtime.bigint at module initialization time\n  const hrTimeBigint = process.hrtime.bigint\n  process.hrtime.bigint = () => 100000000000000n\n\n  const pino = require('../')\n\n  const opts = {\n    timestamp: pino.stdTimeFunctions.isoTimeNano\n  }\n  const stream = sink()\n\n  // Mock process.hrtime.bigint at invocation time, add 1 day to the timestamp\n  process.hrtime.bigint = () => 100000000000000n + 86400012345678n\n\n  const instance = pino(opts, stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.equal(result.time, '2025-08-02T15:03:45.012345678Z')\n\n  Date.now = now\n  process.hrtime.bigint = hrTimeBigint\n})\n"
  },
  {
    "path": "test/timestamp.test.js",
    "content": "'use strict'\n\n/* eslint no-prototype-builtins: 0 */\n\nconst test = require('node:test')\nconst assert = require('node:assert')\n\nconst { sink, once } = require('./helper')\nconst pino = require('../')\n\ntest('pino exposes standard time functions', async () => {\n  assert.ok(pino.stdTimeFunctions)\n  assert.ok(pino.stdTimeFunctions.epochTime)\n  assert.ok(pino.stdTimeFunctions.unixTime)\n  assert.ok(pino.stdTimeFunctions.nullTime)\n  assert.ok(pino.stdTimeFunctions.isoTime)\n  assert.ok(pino.stdTimeFunctions.isoTimeNano)\n})\n\ntest('pino accepts external time functions', async () => {\n  const opts = {\n    timestamp: () => ',\"time\":\"none\"'\n  }\n  const stream = sink()\n  const instance = pino(opts, stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.equal(result.time, 'none')\n})\n\ntest('pino accepts external time functions with custom label', async () => {\n  const opts = {\n    timestamp: () => ',\"custom-time-label\":\"none\"'\n  }\n  const stream = sink()\n  const instance = pino(opts, stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('custom-time-label'), true)\n  assert.equal(result['custom-time-label'], 'none')\n})\n\ntest('inserts timestamp by default', async ({ ok, equal }) => {\n  const stream = sink()\n  const instance = pino(stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than timestamp')\n  assert.equal(result.msg, 'foobar')\n})\n\ntest('omits timestamp when timestamp option is false', async () => {\n  const stream = sink()\n  const instance = pino({ timestamp: false }, stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), false)\n  assert.equal(result.msg, 'foobar')\n})\n\ntest('inserts timestamp when timestamp option is true', async ({ ok, equal }) => {\n  const stream = sink()\n  const instance = pino({ timestamp: true }, stream)\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than timestamp')\n  assert.equal(result.msg, 'foobar')\n})\n\ntest('child inserts timestamp by default', async ({ ok, equal }) => {\n  const stream = sink()\n  const logger = pino(stream)\n  const instance = logger.child({ component: 'child' })\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.ok(new Date(result.time) <= new Date(), 'time is greater than timestamp')\n  assert.equal(result.msg, 'foobar')\n})\n\ntest('child omits timestamp with option', async () => {\n  const stream = sink()\n  const logger = pino({ timestamp: false }, stream)\n  const instance = logger.child({ component: 'child' })\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), false)\n  assert.equal(result.msg, 'foobar')\n})\n\ntest('pino.stdTimeFunctions.unixTime returns seconds based timestamps', async () => {\n  const opts = {\n    timestamp: pino.stdTimeFunctions.unixTime\n  }\n  const stream = sink()\n  const instance = pino(opts, stream)\n  const now = Date.now\n  Date.now = () => 1531069919686\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.equal(result.time, 1531069920)\n  Date.now = now\n})\n\ntest('pino.stdTimeFunctions.isoTime returns ISO 8601 timestamps', async () => {\n  const opts = {\n    timestamp: pino.stdTimeFunctions.isoTime\n  }\n  const stream = sink()\n  const instance = pino(opts, stream)\n  const ms = 1531069919686\n  const now = Date.now\n  Date.now = () => ms\n  const iso = new Date(ms).toISOString()\n  instance.info('foobar')\n  const result = await once(stream, 'data')\n  assert.equal(result.hasOwnProperty('time'), true)\n  assert.equal(result.time, iso)\n  Date.now = now\n})\n"
  },
  {
    "path": "test/transport/big.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { createReadStream } = require('node:fs')\nconst { promisify } = require('node:util')\nconst stream = require('node:stream')\nconst execa = require('execa')\nconst split = require('split2')\n\nconst { file } = require('../helper')\n\nconst pipeline = promisify(stream.pipeline)\nconst { Writable } = stream\nconst sleep = promisify(setTimeout)\n\nconst skip = process.env.CI || process.env.CITGM\n\ntest('eight million lines', { skip }, async () => {\n  const destination = file()\n  await execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-many-lines.js'), destination])\n\n  if (process.platform !== 'win32') {\n    try {\n      await execa('sync') // Wait for the file to be written to disk\n    } catch {\n      // Just a fallback, this should be unreachable\n    }\n  }\n  await sleep(1_000) // It seems that sync is not enough (even in POSIX systems)\n\n  const toWrite = 8 * 1_000_000\n  let count = 0\n  await pipeline(createReadStream(destination), split(), new Writable({\n    write (chunk, enc, cb) {\n      count++\n      cb()\n    }\n  }))\n  assert.equal(count, toWrite)\n})\n"
  },
  {
    "path": "test/transport/bundlers-support.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { readFile } = require('node:fs').promises\n\nconst { watchFileCreated, file } = require('../helper')\nconst pino = require('../../pino')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('pino.transport with destination overridden by bundler', async (t) => {\n  globalThis.__bundlerPathsOverrides = {\n    foobar: join(__dirname, '..', 'fixtures', 'to-file-transport.js')\n  }\n\n  const destination = file()\n  const transport = pino.transport({\n    target: 'foobar',\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n\n  globalThis.__bundlerPathsOverrides = undefined\n})\n\ntest('pino.transport with worker destination overridden by bundler', async (t) => {\n  globalThis.__bundlerPathsOverrides = {\n    'pino-worker': join(__dirname, '..', '..', 'lib/worker.js')\n  }\n\n  const destination = file()\n  const transport = pino.transport({\n    targets: [\n      {\n        target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n        options: { destination }\n      }\n    ]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n\n  globalThis.__bundlerPathsOverrides = undefined\n})\n\ntest('pino.transport with worker destination overridden by bundler and mjs transport', async (t) => {\n  globalThis.__bundlerPathsOverrides = {\n    'pino-worker': join(__dirname, '..', '..', 'lib/worker.js')\n  }\n\n  const destination = file()\n  const transport = pino.transport({\n    targets: [\n      {\n        target: join(__dirname, '..', 'fixtures', 'ts', 'to-file-transport.es2017.cjs'),\n        options: { destination }\n      }\n    ]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n\n  globalThis.__bundlerPathsOverrides = undefined\n})\n"
  },
  {
    "path": "test/transport/caller.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst execa = require('execa')\n\ntest('when using a custom transport outside node_modules, the first file outside node_modules should be used', async function () {\n  const evalApp = join(__dirname, '../', '/fixtures/eval/index.js')\n  const { stdout } = await execa(process.argv[0], [evalApp])\n  assert.match(stdout, /done!/)\n})\n\ntest('when using a custom transport where some files in stacktrace are in the node_modules, the first file outside node_modules should be used', async function () {\n  const evalApp = join(__dirname, '../', '/fixtures/eval/node_modules/2-files.js')\n  const { stdout } = await execa(process.argv[0], [evalApp])\n  assert.match(stdout, /done!/)\n})\n\ntest('when using a custom transport where all files in stacktrace are in the node_modules, the first file inside node_modules should be used', async function () {\n  const evalApp = join(__dirname, '../', '/fixtures/eval/node_modules/14-files.js')\n  const { stdout } = await execa(process.argv[0], [evalApp])\n  assert.match(stdout, /done!/)\n})\n"
  },
  {
    "path": "test/transport/core.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { once } = require('node:events')\nconst { setImmediate: immediate } = require('node:timers/promises')\nconst { readFile, writeFile } = require('node:fs').promises\nconst url = require('url')\nconst strip = require('strip-ansi')\nconst execa = require('execa')\nconst writer = require('flush-write-stream')\nconst rimraf = require('rimraf')\nconst tspl = require('@matteo.collina/tspl')\n\nconst { match, watchFileCreated, watchForWrite, file } = require('../helper')\nconst pino = require('../../')\n\nconst { tmpdir } = os\nconst pid = process.pid\nconst hostname = os.hostname()\n\ntest('pino.transport with file', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with file (no options + error handling)', async () => {\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js')\n  })\n  const [err] = await once(transport, 'error')\n  assert.equal(err.message, 'kaboom')\n})\n\ntest('pino.transport with file URL', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: url.pathToFileURL(join(__dirname, '..', 'fixtures', 'to-file-transport.js')).href,\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport errors if file does not exists', (t, end) => {\n  const instance = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'non-existent-file'),\n    worker: {\n      stdin: true,\n      stdout: true,\n      stderr: true\n    }\n  })\n  instance.on('error', function () {\n    assert.ok('error received')\n    end()\n  })\n})\n\ntest('pino.transport errors if transport worker module does not export a function', async (t) => {\n  // TODO: add case for non-pipelined single target (needs changes in thread-stream)\n  const plan = tspl(t, { plan: 2 })\n  const manyTargetsInstance = pino.transport({\n    targets: [{\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js')\n    }, {\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js')\n    }]\n  })\n  manyTargetsInstance.on('error', function (e) {\n    plan.equal(e.message, 'exported worker is not a function')\n  })\n\n  const pipelinedInstance = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-wrong-export-type.js')\n    }]\n  })\n  pipelinedInstance.on('error', function (e) {\n    plan.equal(e.message, 'exported worker is not a function')\n  })\n\n  await plan\n})\n\ntest('pino.transport with esm', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.mjs'),\n    options: { destination }\n  })\n  const instance = pino(transport)\n  t.after(transport.end.bind(transport))\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with two files', async (t) => {\n  const dest1 = file()\n  const dest2 = file()\n  const transport = pino.transport({\n    targets: [{\n      level: 'info',\n      target: 'file://' + join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest1 }\n    }, {\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest2 }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n  const result1 = JSON.parse(await readFile(dest1))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n  const result2 = JSON.parse(await readFile(dest2))\n  delete result2.time\n  assert.deepEqual(result2, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with two files and custom levels', async (t) => {\n  const dest1 = file()\n  const dest2 = file()\n  const transport = pino.transport({\n    targets: [{\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest1 }\n    }, {\n      level: 'foo',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest2 }\n    }],\n    levels: { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, foo: 25 }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n  const result1 = JSON.parse(await readFile(dest1))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n  const result2 = JSON.parse(await readFile(dest2))\n  delete result2.time\n  assert.deepEqual(result2, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport without specifying default levels', async (t) => {\n  const dest = file()\n  const transport = pino.transport({\n    targets: [{\n      level: 'foo',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest }\n    }],\n    levels: { foo: 25 }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await Promise.all([watchFileCreated(dest)])\n  const result1 = JSON.parse(await readFile(dest))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with two files and dedupe', async (t) => {\n  const dest1 = file()\n  const dest2 = file()\n  const transport = pino.transport({\n    dedupe: true,\n    targets: [{\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest1 }\n    }, {\n      level: 'error',\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination: dest2 }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  instance.error('world')\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n  const result1 = JSON.parse(await readFile(dest1))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n  const result2 = JSON.parse(await readFile(dest2))\n  delete result2.time\n  assert.deepEqual(result2, {\n    pid,\n    hostname,\n    level: 50,\n    msg: 'world'\n  })\n})\n\ntest('pino.transport with an array including a pino-pretty destination', async (t) => {\n  const dest1 = file()\n  const dest2 = file()\n  const transport = pino.transport({\n    targets: [{\n      level: 'info',\n      target: 'pino/file',\n      options: {\n        destination: dest1\n      }\n    }, {\n      level: 'info',\n      target: 'pino-pretty',\n      options: {\n        destination: dest2\n      }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n  const result1 = JSON.parse(await readFile(dest1))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n  const actual = (await readFile(dest2)).toString()\n  assert.match(strip(actual), /\\[.*\\] INFO.*hello/)\n})\n\ntest('no transport.end()', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination }\n  })\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('autoEnd = false', async (t) => {\n  const destination = file()\n  const count = process.listenerCount('exit')\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination },\n    worker: { autoEnd: false }\n  })\n  t.after(transport.end.bind(transport))\n  await once(transport, 'ready')\n\n  const instance = pino(transport)\n  instance.info('hello')\n\n  await watchFileCreated(destination)\n\n  assert.equal(count, process.listenerCount('exit'))\n\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with target and targets', async () => {\n  assert.throws(\n    () => {\n      pino.transport({\n        target: '/a/file',\n        targets: [{\n          target: '/a/file'\n        }]\n      })\n    },\n    /only one of target or targets can be specified/\n  )\n})\n\ntest('pino.transport with target pino/file', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: 'pino/file',\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with target pino/file and mkdir option', async (t) => {\n  const folder = join(tmpdir(), `pino-${process.pid}-mkdir-transport-file`)\n  const destination = join(folder, 'log.txt')\n  t.after(() => {\n    try {\n      rimraf.sync(folder)\n    } catch (err) {\n      // ignore\n    }\n  })\n  const transport = pino.transport({\n    target: 'pino/file',\n    options: { destination, mkdir: true }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('pino.transport with target pino/file and append option', async (t) => {\n  const destination = file()\n  await writeFile(destination, JSON.stringify({ pid, hostname, time: Date.now(), level: 30, msg: 'hello' }))\n  const transport = pino.transport({\n    target: 'pino/file',\n    options: { destination, append: false }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('goodbye')\n  await watchForWrite(destination, '\"goodbye\"')\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'goodbye'\n  })\n})\n\ntest('pino.transport should error with unknown target', async () => {\n  assert.throws(\n    () => {\n      pino.transport({\n        target: 'origin',\n        caller: 'unknown-file.js'\n      })\n    },\n    /unable to determine transport target for \"origin\"/\n  )\n})\n\ntest('pino.transport with target pino-pretty', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    target: 'pino-pretty',\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const actual = await readFile(destination, 'utf8')\n  assert.match(strip(actual), /\\[.*\\] INFO.*hello/)\n})\n\ntest('sets worker data informing the transport that pino will send its config', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'transport-worker-data.js')\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  transport.once('workerData', (workerData) => {\n    match(workerData.workerData, { pinoWillSendConfig: true })\n    plan.ok('passed')\n  })\n  instance.info('hello')\n\n  await plan\n})\n\ntest('sets worker data informing the transport that pino will send its config (frozen file)', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const config = {\n    transport: {\n      target: join(__dirname, '..', 'fixtures', 'transport-worker-data.js'),\n      options: {}\n    }\n  }\n  Object.freeze(config)\n  Object.freeze(config.transport)\n  Object.freeze(config.transport.options)\n  const instance = pino(config)\n  const transport = instance[pino.symbols.streamSym]\n  t.after(transport.end.bind(transport))\n  transport.once('workerData', (workerData) => {\n    match(workerData.workerData, { pinoWillSendConfig: true })\n    plan.ok('passed')\n  })\n  instance.info('hello')\n\n  await plan\n})\n\ntest('warns when custom formatters.level is incompatible with multi-target transport routing', async (t) => {\n  const warnings = []\n  const originalEmitWarning = process.emitWarning\n  process.emitWarning = function (warning, options) {\n    warnings.push({ warning, options })\n  }\n  t.after(() => {\n    process.emitWarning = originalEmitWarning\n  })\n\n  const transport = pino.transport({\n    targets: [\n      { target: join(__dirname, '..', 'fixtures', 'noop-transport.js') },\n      { target: join(__dirname, '..', 'fixtures', 'noop-transport.js') }\n    ]\n  })\n  t.after(transport.end.bind(transport))\n\n  const instance = pino({\n    formatters: {\n      level (label) {\n        return { severity: label }\n      }\n    }\n  }, transport)\n\n  instance.info('hello')\n\n  assert.equal(warnings.length, 1)\n  assert.equal(warnings[0].options.code, 'PINO_TRANSPORT_MULTI_TARGETS_LEVEL_FORMATTER')\n})\n\ntest('stdout in worker', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-main.js')])\n\n  for await (const chunk of child.stdout) {\n    actual += chunk\n  }\n  assert.equal(strip(actual).match(/Hello/) != null, true)\n})\n\ntest('log and exit on ready', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-exit-on-ready.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n  await once(child, 'close')\n  await immediate()\n  assert.equal(strip(actual).match(/Hello/) != null, true)\n})\n\ntest('log and exit before ready', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-exit-immediately.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n  await once(child, 'close')\n  await immediate()\n  assert.equal(strip(actual).match(/Hello/) != null, true)\n})\n\ntest('log and exit before ready with async dest', async () => {\n  const destination = file()\n  const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-exit-immediately-with-async-dest.js'), destination])\n\n  await once(child, 'exit')\n\n  const actual = await readFile(destination, 'utf8')\n  assert.equal(strip(actual).match(/HELLO/) != null, true)\n  assert.equal(strip(actual).match(/WORLD/) != null, true)\n})\n\ntest('string integer destination', async () => {\n  let actual = ''\n  const child = execa(process.argv[0], [join(__dirname, '..', 'fixtures', 'transport-string-stdout.js')])\n\n  child.stdout.pipe(writer((s, enc, cb) => {\n    actual += s\n    cb()\n  }))\n  await once(child, 'close')\n  await immediate()\n  assert.equal(strip(actual).match(/Hello/) != null, true)\n})\n\ntest('pino transport options with target', async (t) => {\n  const destination = file()\n  const instance = pino({\n    transport: {\n      target: 'pino/file',\n      options: { destination }\n    }\n  })\n  const transportStream = instance[pino.symbols.streamSym]\n  t.after(transportStream.end.bind(transportStream))\n  instance.info('transport option test')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'transport option test'\n  })\n})\n\ntest('pino transport options with targets', async (t) => {\n  const dest1 = file()\n  const dest2 = file()\n  const instance = pino({\n    transport: {\n      targets: [\n        { target: 'pino/file', options: { destination: dest1 } },\n        { target: 'pino/file', options: { destination: dest2 } }\n      ]\n    }\n  })\n  const transportStream = instance[pino.symbols.streamSym]\n  t.after(transportStream.end.bind(transportStream))\n  instance.info('transport option test')\n\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n  const result1 = JSON.parse(await readFile(dest1))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'transport option test'\n  })\n  const result2 = JSON.parse(await readFile(dest2))\n  delete result2.time\n  assert.deepEqual(result2, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'transport option test'\n  })\n})\n\ntest('transport options with target and targets', async () => {\n  assert.throws(\n    () => {\n      pino({\n        transport: {\n          target: {},\n          targets: {}\n        }\n      })\n    },\n    /only one of target or targets can be specified/\n  )\n})\n\ntest('transport options with target and stream', async () => {\n  assert.throws(\n    () => {\n      pino({\n        transport: {\n          target: {}\n        }\n      }, '/log/null')\n    },\n    /only one of option.transport or stream can be specified/\n  )\n})\n\ntest('transport options with stream', async (t) => {\n  const dest1 = file()\n  const transportStream = pino.transport({ target: 'pino/file', options: { destination: dest1 } })\n  t.after(transportStream.end.bind(transportStream))\n  assert.throws(\n    () => {\n      pino({\n        transport: transportStream\n      })\n    },\n    Error('option.transport do not allow stream, please pass to option directly. e.g. pino(transport)')\n  )\n})\n\ntest('pino.transport handles prototype pollution of __bundlerPathsOverrides', async (t) => {\n  // eslint-disable-next-line no-extend-native\n  Object.prototype.__bundlerPathsOverrides = { 'pino/file': '/malicious/path' }\n  t.after(() => {\n    delete Object.prototype.__bundlerPathsOverrides\n  })\n\n  const destination = file()\n  const transport = pino.transport({\n    target: 'pino/file',\n    options: { destination }\n  })\n  t.after(transport.end.bind(transport))\n\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\nconst hasThreadName = 'threadName' in require('worker_threads')\n\ntest('pino.transport with single target sets worker thread name to target', { skip: !hasThreadName }, async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'transport-worker-name.js')\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  transport.once('workerThreadName', (name) => {\n    plan.equal(name, join(__dirname, '..', 'fixtures', 'transport-worker-name.js'))\n  })\n  instance.info('hello')\n\n  await plan\n})\n\ntest('pino.transport with targets sets worker thread name to pino.transport', { skip: !hasThreadName }, async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const transport = pino.transport({\n    targets: [{\n      level: 'info',\n      target: join(__dirname, '..', 'fixtures', 'transport-worker-name.js')\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  transport.once('workerThreadName', (name) => {\n    plan.equal(name, 'pino.transport')\n  })\n  instance.info('hello')\n\n  await plan\n})\n\ntest('pino.transport with pipeline sets worker thread name to pino.transport', { skip: !hasThreadName }, async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const transport = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-worker-name.js')\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  transport.once('workerThreadName', (name) => {\n    plan.equal(name, 'pino.transport')\n  })\n  instance.info('hello')\n\n  await plan\n})\n"
  },
  {
    "path": "test/transport/core.transpiled.test.ts",
    "content": "import test from 'node:test'\nimport assert from 'node:assert'\nimport * as os from 'node:os'\nimport { join } from 'node:path'\nimport fs from 'node:fs'\nimport * as url from 'node:url'\n\nimport { watchFileCreated } from '../helper'\nimport pino from '../../'\n\nconst readFile = fs.promises.readFile\n\nconst { pid } = process\nconst hostname = os.hostname()\n\n// A subset of the test from core.test.js, we don't need all of them to check for compatibility\nfunction runTests (esVersion: string): void {\n  test(`(ts -> ${esVersion}) pino.transport with file`, async (t) => {\n    const destination = join(\n      os.tmpdir(),\n      '_' + Math.random().toString(36).substr(2, 9)\n    )\n    const transport = pino.transport({\n      target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),\n      options: { destination }\n    })\n    t.after(transport.end.bind(transport))\n    const instance = pino(transport)\n    instance.info('hello')\n    await watchFileCreated(destination)\n    const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'hello'\n    })\n  })\n\n  test(`(ts -> ${esVersion}) pino.transport with file URL`, async (t) => {\n    const destination = join(\n      os.tmpdir(),\n      '_' + Math.random().toString(36).substr(2, 9)\n    )\n    const transport = pino.transport({\n      target: url.pathToFileURL(join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`)).href,\n      options: { destination }\n    })\n    t.after(transport.end.bind(transport))\n    const instance = pino(transport)\n    instance.info('hello')\n    await watchFileCreated(destination)\n    const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))\n    delete result.time\n    assert.deepEqual(result, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'hello'\n    })\n  })\n\n  test(`(ts -> ${esVersion}) pino.transport with two files`, async (t) => {\n    const dest1 = join(\n      os.tmpdir(),\n      '_' + Math.random().toString(36).substr(2, 9)\n    )\n    const dest2 = join(\n      os.tmpdir(),\n      '_' + Math.random().toString(36).substr(2, 9)\n    )\n    const transport = pino.transport({\n      targets: [{\n        level: 'info',\n        target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),\n        options: { destination: dest1 }\n      }, {\n        level: 'info',\n        target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),\n        options: { destination: dest2 }\n      }]\n    })\n\n    t.after(transport.end.bind(transport))\n\n    const instance = pino(transport)\n    instance.info('hello')\n\n    await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n\n    const result1 = JSON.parse(await readFile(dest1, { encoding: 'utf8' }))\n    delete result1.time\n    assert.deepEqual(result1, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'hello'\n    })\n    const result2 = JSON.parse(await readFile(dest2, { encoding: 'utf8' }))\n    delete result2.time\n    assert.deepEqual(result2, {\n      pid,\n      hostname,\n      level: 30,\n      msg: 'hello'\n    })\n  })\n}\n\nrunTests('es5')\nrunTests('es6')\nrunTests('es2017')\nrunTests('esnext')\n"
  },
  {
    "path": "test/transport/crash.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { once } = require('node:events')\nconst { setImmediate: immediate } = require('node:timers/promises')\n\nconst pino = require('../../')\n\ntest('pino.transport emits error if the worker exits with 0 unexpectably', async (t) => {\n  // This test will take 10s, because flushSync waits for 10s\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'crashing-transport.js'),\n    sync: true\n  })\n  t.after(transport.end.bind(transport))\n\n  await once(transport, 'ready')\n\n  let maybeError\n  transport.on('error', (err) => {\n    maybeError = err\n  })\n\n  const logger = pino(transport)\n  for (let i = 0; i < 100000; i++) {\n    logger.info('hello')\n  }\n\n  await once(transport.worker, 'exit')\n\n  await immediate()\n\n  assert.equal(maybeError.message, 'the worker has exited')\n})\n"
  },
  {
    "path": "test/transport/module-link.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { readFile, symlink, unlink, mkdir, writeFile } = require('node:fs').promises\nconst { once } = require('node:events')\nconst execa = require('execa')\nconst rimraf = require('rimraf')\n\nconst { isWin, isYarnPnp, watchFileCreated, file } = require('../helper')\nconst pino = require('../../')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\nasync function installTransportModule (target) {\n  if (isYarnPnp) {\n    return\n  }\n  try {\n    await uninstallTransportModule()\n  } catch {}\n\n  if (!target) {\n    target = join(__dirname, '..', '..')\n  }\n\n  await symlink(\n    join(__dirname, '..', 'fixtures', 'transport'),\n    join(target, 'node_modules', 'transport')\n  )\n}\n\nasync function uninstallTransportModule () {\n  if (isYarnPnp) {\n    return\n  }\n  await unlink(join(__dirname, '..', '..', 'node_modules', 'transport'))\n}\n\n// TODO make this test pass on Windows\ntest('pino.transport with package', { skip: isWin }, async (t) => {\n  const destination = file()\n\n  await installTransportModule()\n\n  const transport = pino.transport({\n    target: 'transport',\n    options: { destination }\n  })\n\n  t.after(async () => {\n    await uninstallTransportModule()\n    transport.end()\n  })\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\n// TODO make this test pass on Windows\ntest('pino.transport with package as a target', { skip: isWin }, async (t) => {\n  const destination = file()\n\n  await installTransportModule()\n\n  const transport = pino.transport({\n    targets: [{\n      target: 'transport',\n      options: { destination }\n    }]\n  })\n  t.after(async () => {\n    await uninstallTransportModule()\n    transport.end()\n  })\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\n// TODO make this test pass on Windows\ntest('pino({ transport })', { skip: isWin || isYarnPnp }, async (t) => {\n  const folder = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  t.after(() => {\n    rimraf.sync(folder)\n  })\n\n  const destination = join(folder, 'output')\n\n  await mkdir(join(folder, 'node_modules'), { recursive: true })\n\n  // Link pino\n  await symlink(\n    join(__dirname, '..', '..'),\n    join(folder, 'node_modules', 'pino')\n  )\n\n  await installTransportModule(folder)\n\n  const toRun = join(folder, 'index.js')\n\n  const toRunContent = `\n    const pino = require('pino')\n    const logger = pino({\n      transport: {\n        target: 'transport',\n        options: { destination: '${destination}' }\n      }\n    })\n    logger.info('hello')\n  `\n\n  await writeFile(toRun, toRunContent)\n\n  const child = execa(process.argv[0], [toRun])\n\n  await once(child, 'close')\n\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid: child.pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\n// TODO make this test pass on Windows\ntest('pino({ transport }) from a wrapped dependency', { skip: isWin || isYarnPnp }, async (t) => {\n  const folder = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  const wrappedFolder = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  const destination = join(folder, 'output')\n\n  await mkdir(join(folder, 'node_modules'), { recursive: true })\n  await mkdir(join(wrappedFolder, 'node_modules'), { recursive: true })\n\n  t.after(() => {\n    rimraf.sync(wrappedFolder)\n    rimraf.sync(folder)\n  })\n\n  // Link pino\n  await symlink(\n    join(__dirname, '..', '..'),\n    join(wrappedFolder, 'node_modules', 'pino')\n  )\n\n  // Link get-caller-file\n  await symlink(\n    join(__dirname, '..', '..', 'node_modules', 'get-caller-file'),\n    join(wrappedFolder, 'node_modules', 'get-caller-file')\n  )\n\n  // Link wrapped\n  await symlink(\n    wrappedFolder,\n    join(folder, 'node_modules', 'wrapped')\n  )\n\n  await installTransportModule(folder)\n\n  const pkgjsonContent = {\n    name: 'pino'\n  }\n\n  await writeFile(join(wrappedFolder, 'package.json'), JSON.stringify(pkgjsonContent))\n\n  const wrapped = join(wrappedFolder, 'index.js')\n\n  const wrappedContent = `\n    const pino = require('pino')\n    const getCaller = require('get-caller-file')\n\n    module.exports = function build () {\n      const logger = pino({\n        transport: {\n          caller: getCaller(),\n          target: 'transport',\n          options: { destination: '${destination}' }\n        }\n      })\n      return logger\n    }\n  `\n\n  await writeFile(wrapped, wrappedContent)\n\n  const toRun = join(folder, 'index.js')\n\n  const toRunContent = `\n    const logger = require('wrapped')()\n    logger.info('hello')\n  `\n\n  await writeFile(toRun, toRunContent)\n\n  const child = execa(process.argv[0], [toRun])\n\n  await once(child, 'close')\n\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid: child.pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n"
  },
  {
    "path": "test/transport/native-type-stripping.test.mjs",
    "content": "import test from 'node:test'\nimport assert from 'node:assert'\nimport * as os from 'node:os'\nimport { join } from 'node:path'\nimport fs from 'node:fs'\nimport * as url from 'node:url'\n\nimport { watchFileCreated } from '../helper.js'\n\nconst readFile = fs.promises.readFile\n\nconst { pid } = process\nconst hostname = os.hostname()\n\n// Check if Node.js supports native type stripping (Node.js 22+)\nfunction supportsTypeStripping () {\n  const major = parseInt(process.versions.node.split('.')[0], 10)\n  return major >= 22\n}\n\n// Only run these tests on Node.js 22+\nconst skipTests = !supportsTypeStripping()\nconst skipMessage = 'Native TypeScript type stripping not supported (requires Node.js 22+)'\n\ntest('pino.transport with native TypeScript file', { skip: skipTests ? skipMessage : false }, async (t) => {\n  const destination = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  // We need to dynamically import pino to ensure worker thread inherits flags\n  const { default: pino } = await import('../../pino.js')\n\n  const transport = pino.transport({\n    target: join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts', 'to-file-transport-native.mts'),\n    options: { destination }\n  })\n\n  t.after(() => {\n    transport.end()\n    try {\n      fs.unlinkSync(destination)\n    } catch {}\n  })\n\n  const instance = pino(transport)\n  instance.info('hello from native TypeScript transport')\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))\n  delete result.time\n\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello from native TypeScript transport'\n  })\n})\n\ntest('pino.transport with native TypeScript file URL', { skip: skipTests ? skipMessage : false }, async (t) => {\n  const destination = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  const { default: pino } = await import('../../pino.js')\n\n  const transport = pino.transport({\n    target: url.pathToFileURL(join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts', 'to-file-transport-native.mts')).href,\n    options: { destination }\n  })\n\n  t.after(() => {\n    transport.end()\n    try {\n      fs.unlinkSync(destination)\n    } catch {}\n  })\n\n  const instance = pino(transport)\n  instance.info('hello from file URL transport')\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))\n  delete result.time\n\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello from file URL transport'\n  })\n})\n\ntest('pino.transport with multiple native TypeScript targets', { skip: skipTests ? skipMessage : false }, async (t) => {\n  const dest1 = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n  const dest2 = join(\n    os.tmpdir(),\n    '_' + Math.random().toString(36).substr(2, 9)\n  )\n\n  const { default: pino } = await import('../../pino.js')\n  const fixtureDir = join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts')\n\n  const transport = pino.transport({\n    targets: [{\n      level: 'info',\n      target: join(fixtureDir, 'to-file-transport-native.mts'),\n      options: { destination: dest1 }\n    }, {\n      level: 'info',\n      target: join(fixtureDir, 'to-file-transport-native.mts'),\n      options: { destination: dest2 }\n    }]\n  })\n\n  t.after(() => {\n    transport.end()\n    try {\n      fs.unlinkSync(dest1)\n      fs.unlinkSync(dest2)\n    } catch {}\n  })\n\n  const instance = pino(transport)\n  instance.info('hello from multiple targets')\n\n  await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])\n\n  const result1 = JSON.parse(await readFile(dest1, { encoding: 'utf8' }))\n  delete result1.time\n  assert.deepEqual(result1, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello from multiple targets'\n  })\n\n  const result2 = JSON.parse(await readFile(dest2, { encoding: 'utf8' }))\n  delete result2.time\n  assert.deepEqual(result2, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello from multiple targets'\n  })\n})\n"
  },
  {
    "path": "test/transport/node-options.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { EventEmitter } = require('node:events')\nconst { join } = require('node:path')\nconst { pathToFileURL } = require('node:url')\nconst proxyquire = require('proxyquire')\n\nfunction buildTransportWithFakeThreadStream () {\n  let lastCtorOpts\n\n  class FakeThreadStream extends EventEmitter {\n    constructor (opts) {\n      super()\n      this._closed = false\n      lastCtorOpts = opts\n    }\n\n    unref () {}\n    ref () {}\n    flushSync () {}\n    end () {\n      this._closed = true\n      this.emit('close')\n    }\n\n    get closed () {\n      return this._closed\n    }\n  }\n\n  const transport = proxyquire('../../lib/transport', {\n    'thread-stream': FakeThreadStream\n  })\n\n  return {\n    transport,\n    getLastCtorOpts () {\n      return lastCtorOpts\n    }\n  }\n}\n\ntest('pino.transport sanitizes missing absolute preload in NODE_OPTIONS', () => {\n  const previous = process.env.NODE_OPTIONS\n  const missing = join(__dirname, '..', 'fixtures', 'missing-preload.js')\n  process.env.NODE_OPTIONS = `--require ${missing} --trace-warnings`\n\n  const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()\n  transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })\n\n  assert.equal(getLastCtorOpts().workerOpts.env.NODE_OPTIONS, '--trace-warnings')\n\n  if (previous === undefined) {\n    delete process.env.NODE_OPTIONS\n  } else {\n    process.env.NODE_OPTIONS = previous\n  }\n})\n\ntest('pino.transport sanitizes missing file:// preload in NODE_OPTIONS', () => {\n  const previous = process.env.NODE_OPTIONS\n  const missingFileUrl = pathToFileURL(join(__dirname, '..', 'fixtures', 'missing-import.mjs')).href\n  process.env.NODE_OPTIONS = `--import=${missingFileUrl}`\n\n  const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()\n  transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })\n\n  assert.equal(getLastCtorOpts().workerOpts.env.NODE_OPTIONS, '')\n\n  if (previous === undefined) {\n    delete process.env.NODE_OPTIONS\n  } else {\n    process.env.NODE_OPTIONS = previous\n  }\n})\n\ntest('pino.transport keeps relative preload flags in NODE_OPTIONS', () => {\n  const previous = process.env.NODE_OPTIONS\n  process.env.NODE_OPTIONS = '--require ./relative-preload.js'\n\n  const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()\n  transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })\n\n  assert.equal(getLastCtorOpts().workerOpts.env, undefined)\n\n  if (previous === undefined) {\n    delete process.env.NODE_OPTIONS\n  } else {\n    process.env.NODE_OPTIONS = previous\n  }\n})\n\ntest('pino.transport does not override explicit worker.env', () => {\n  const previous = process.env.NODE_OPTIONS\n  process.env.NODE_OPTIONS = `--require ${join(__dirname, '..', 'fixtures', 'missing-preload.js')}`\n\n  const explicitEnv = { NODE_OPTIONS: '--trace-warnings' }\n\n  const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()\n  transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    worker: {\n      env: explicitEnv\n    }\n  })\n\n  assert.equal(getLastCtorOpts().workerOpts.env, explicitEnv)\n\n  if (previous === undefined) {\n    delete process.env.NODE_OPTIONS\n  } else {\n    process.env.NODE_OPTIONS = previous\n  }\n})\n"
  },
  {
    "path": "test/transport/pipeline.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { readFile } = require('node:fs').promises\n\nconst { watchFileCreated, file } = require('../helper')\nconst pino = require('../../')\nconst { DEFAULT_LEVELS } = require('../../lib/constants')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('pino.transport with a pipeline', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-transform.js')\n    }, {\n      target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n      options: { destination }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: DEFAULT_LEVELS.info,\n    msg: 'hello',\n    service: 'pino' // this property was added by the transform\n  })\n})\n\ntest('pino.transport with targets containing pipelines', async (t) => {\n  const destinationA = file()\n  const destinationB = file()\n  const transport = pino.transport({\n    targets: [\n      {\n        target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n        options: { destination: destinationA }\n      },\n      {\n        pipeline: [\n          {\n            target: join(__dirname, '..', 'fixtures', 'transport-transform.js')\n          },\n          {\n            target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n            options: { destination: destinationB }\n          }\n        ]\n      }\n    ]\n  })\n\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello')\n  await watchFileCreated(destinationA)\n  await watchFileCreated(destinationB)\n  const resultA = JSON.parse(await readFile(destinationA))\n  const resultB = JSON.parse(await readFile(destinationB))\n  delete resultA.time\n  delete resultB.time\n  assert.deepEqual(resultA, {\n    pid,\n    hostname,\n    level: DEFAULT_LEVELS.info,\n    msg: 'hello'\n  })\n  assert.deepEqual(resultB, {\n    pid,\n    hostname,\n    level: DEFAULT_LEVELS.info,\n    msg: 'hello',\n    service: 'pino' // this property was added by the transform\n  })\n})\n\ntest('pino.transport with targets containing pipelines with levels defined and dedupe', async (t) => {\n  const destinationA = file()\n  const destinationB = file()\n  const transport = pino.transport({\n    targets: [\n      {\n        target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n        options: { destination: destinationA },\n        level: DEFAULT_LEVELS.info\n      },\n      {\n        pipeline: [\n          {\n            target: join(__dirname, '..', 'fixtures', 'transport-transform.js')\n          },\n          {\n            target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n            options: { destination: destinationB }\n          }\n        ],\n        level: DEFAULT_LEVELS.error\n      }\n    ],\n    dedupe: true\n  })\n\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n  instance.info('hello info')\n  instance.error('hello error')\n  await watchFileCreated(destinationA)\n  await watchFileCreated(destinationB)\n  const resultA = JSON.parse(await readFile(destinationA))\n  const resultB = JSON.parse(await readFile(destinationB))\n  delete resultA.time\n  delete resultB.time\n  assert.deepEqual(resultA, {\n    pid,\n    hostname,\n    level: DEFAULT_LEVELS.info,\n    msg: 'hello info'\n  })\n  assert.deepEqual(resultB, {\n    pid,\n    hostname,\n    level: DEFAULT_LEVELS.error,\n    msg: 'hello error',\n    service: 'pino' // this property was added by the transform\n  })\n})\n"
  },
  {
    "path": "test/transport/preload.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { pathToFileURL } = require('node:url')\nconst { readFile } = require('node:fs').promises\nconst execa = require('execa')\n\nconst { file, watchFileCreated } = require('../helper')\n\ntest('pino.transport works when loaded via --import=preload', async () => {\n  const destination = file()\n  const preload = pathToFileURL(join(__dirname, '..', 'fixtures', 'transport-preload.mjs')).href\n  const main = join(__dirname, '..', 'fixtures', 'transport-preload-main.mjs')\n\n  await execa(process.argv[0], [\n    `--import=${preload}`,\n    main,\n    destination\n  ], { timeout: 10000 })\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  assert.equal(result.msg, 'hello from main')\n})\n\ntest('pino.transport works when loaded via --import preload (space separated)', async () => {\n  const destination = file()\n  const preload = pathToFileURL(join(__dirname, '..', 'fixtures', 'transport-preload.mjs')).href\n  const main = join(__dirname, '..', 'fixtures', 'transport-preload-main.mjs')\n\n  await execa(process.argv[0], [\n    '--import',\n    preload,\n    main,\n    destination\n  ], { timeout: 10000 })\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  assert.equal(result.msg, 'hello from main')\n})\n\ntest('pino.transport ignores missing absolute preload from NODE_OPTIONS in worker', async () => {\n  const destination = file()\n  const main = join(__dirname, '..', 'fixtures', 'transport-invalid-node-options.js')\n\n  await execa(process.argv[0], [main, destination], { timeout: 10000 })\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  assert.equal(result.msg, 'hello with invalid node options preload')\n})\n"
  },
  {
    "path": "test/transport/repl.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst proxyquire = require('proxyquire')\n\ntest('pino.transport resolves targets in REPL', async () => {\n  // Arrange\n  const transport = proxyquire('../../lib/transport', {\n    './caller': () => ['node:repl']\n  })\n\n  // Act / Assert\n  assert.doesNotThrow(() => transport({ target: 'pino-pretty' }))\n})\n"
  },
  {
    "path": "test/transport/sync-false.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { readFile } = require('node:fs').promises\nconst { promisify } = require('node:util')\n\nconst pino = require('../..')\nconst { watchFileCreated, watchForWrite, file } = require('../helper')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\ntest('thread-stream async flush', async () => {\n  const destination = file()\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination }\n  })\n  const instance = pino(transport)\n  instance.info('hello')\n\n  assert.equal(instance.flush(), undefined)\n\n  await watchFileCreated(destination)\n  const result = JSON.parse(await readFile(destination))\n  delete result.time\n  assert.deepEqual(result, {\n    pid,\n    hostname,\n    level: 30,\n    msg: 'hello'\n  })\n})\n\ntest('thread-stream async flush should call the passed callback', async () => {\n  const outputPath = file()\n  async function getOutputLogLines () {\n    return (await readFile(outputPath)).toString().trim().split('\\n').map(JSON.parse)\n  }\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination: outputPath }\n  })\n  const instance = pino(transport)\n  const flushPromise = promisify(instance.flush).bind(instance)\n\n  instance.info('hello')\n  await flushPromise()\n  await watchFileCreated(outputPath)\n\n  const [firstFlushData] = await getOutputLogLines()\n\n  assert.equal(firstFlushData.msg, 'hello')\n\n  instance.info('world')\n\n  await flushPromise()\n  await watchForWrite(outputPath, 'world')\n\n  // After flush, both messages should be present\n  const afterSecondFlush = await getOutputLogLines()\n  assert.equal(afterSecondFlush.length, 2)\n  assert.equal(afterSecondFlush[1].msg, 'world')\n})\n"
  },
  {
    "path": "test/transport/sync-true.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst { join } = require('node:path')\nconst { readFileSync } = require('node:fs')\n\nconst { file } = require('../helper')\nconst pino = require('../..')\n\ntest('thread-stream sync true should log synchronously', async () => {\n  const outputPath = file()\n\n  function getOutputLogLines () {\n    return (readFileSync(outputPath)).toString().trim().split('\\n').map(JSON.parse)\n  }\n\n  const transport = pino.transport({\n    target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),\n    options: { destination: outputPath, flush: true },\n    sync: true\n  })\n  const instance = pino(transport)\n\n  var value = { message: 'sync' }\n  instance.info(value)\n  instance.info(value)\n  instance.info(value)\n  instance.info(value)\n  instance.info(value)\n  instance.info(value)\n  let interrupt = false\n  let flushData\n  let loopCounter = 0\n\n  // Start a synchronous loop\n  while (!interrupt && loopCounter < (process.env.MAX_TEST_LOOP_ITERATION || 20000)) {\n    try {\n      loopCounter++\n      const data = getOutputLogLines()\n      flushData = data\n      if (data) {\n        interrupt = true\n        break\n      }\n    } catch (error) {\n      // File may not exist yet\n      // Wait till MAX_TEST_LOOP_ITERATION iterations\n    }\n  }\n\n  if (!interrupt) {\n    throw new Error('Sync loop did not get interrupt')\n  }\n\n  assert.equal(flushData.length, 6)\n})\n"
  },
  {
    "path": "test/transport/targets.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst { join } = require('node:path')\nconst Writable = require('node:stream').Writable\nconst proxyquire = require('proxyquire')\nconst tspl = require('@matteo.collina/tspl')\nconst pino = require('../../pino')\n\ntest('file-target mocked', async function (t) {\n  const plan = tspl(t, { plan: 1 })\n  let ret\n  const fileTarget = proxyquire('../../file', {\n    './pino': {\n      destination (opts) {\n        plan.deepEqual(opts, { dest: 1, sync: false })\n\n        ret = new Writable()\n        ret.fd = opts.dest\n\n        process.nextTick(() => {\n          ret.emit('ready')\n        })\n\n        return ret\n      }\n    }\n  })\n\n  await fileTarget()\n  await plan\n})\n\ntest('pino.transport with syntax error', async (t) => {\n  const plan = tspl(t, { plan: 1 })\n  const transport = pino.transport({\n    targets: [{\n      target: join(__dirname, '..', 'fixtures', 'syntax-error-esm.mjs')\n    }]\n  })\n  t.after(transport.end.bind(transport))\n\n  transport.on('error', (err) => {\n    plan.deepEqual(err, new SyntaxError('Unexpected end of input'))\n  })\n\n  await plan\n})\n"
  },
  {
    "path": "test/transport/uses-pino-config.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst assert = require('node:assert')\nconst os = require('node:os')\nconst { join } = require('node:path')\nconst { readFile } = require('node:fs').promises\nconst writeStream = require('flush-write-stream')\n\nconst { watchFileCreated, file } = require('../helper')\nconst pino = require('../../')\n\nconst { pid } = process\nconst hostname = os.hostname()\n\nfunction serializeError (error) {\n  return {\n    type: error.name,\n    message: error.message,\n    stack: error.stack\n  }\n}\n\nfunction parseLogs (buffer) {\n  return JSON.parse(`[${buffer.toString().replace(/}{/g, '},{')}]`)\n}\n\ntest('transport uses pino config', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-uses-pino-config.js')\n    }, {\n      target: 'pino/file',\n      options: { destination }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino({\n    messageKey: 'customMessageKey',\n    errorKey: 'customErrorKey',\n    customLevels: { custom: 35 }\n  }, transport)\n\n  const error = new Error('bar')\n  instance.custom('foo')\n  instance.error(error)\n  await watchFileCreated(destination)\n  const result = parseLogs(await readFile(destination))\n\n  assert.deepEqual(result, [{\n    severityText: 'custom',\n    body: 'foo',\n    attributes: {\n      pid,\n      hostname\n    }\n  }, {\n    severityText: 'error',\n    body: 'bar',\n    attributes: {\n      pid,\n      hostname\n    },\n    error: serializeError(error)\n  }])\n})\n\ntest('transport uses pino config without customizations', async (t) => {\n  const destination = file()\n  const transport = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-uses-pino-config.js')\n    }, {\n      target: 'pino/file',\n      options: { destination }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino(transport)\n\n  const error = new Error('qux')\n  instance.info('baz')\n  instance.error(error)\n  await watchFileCreated(destination)\n  const result = parseLogs(await readFile(destination))\n\n  assert.deepEqual(result, [{\n    severityText: 'info',\n    body: 'baz',\n    attributes: {\n      pid,\n      hostname\n    }\n  }, {\n    severityText: 'error',\n    body: 'qux',\n    attributes: {\n      pid,\n      hostname\n    },\n    error: serializeError(error)\n  }])\n})\n\ntest('transport uses pino config with multistream', async (t) => {\n  const destination = file()\n  const messages = []\n  const stream = writeStream(function (data, enc, cb) {\n    const message = JSON.parse(data)\n    delete message.time\n    messages.push(message)\n    cb()\n  })\n  const transport = pino.transport({\n    pipeline: [{\n      target: join(__dirname, '..', 'fixtures', 'transport-uses-pino-config.js')\n    }, {\n      target: 'pino/file',\n      options: { destination }\n    }]\n  })\n  t.after(transport.end.bind(transport))\n  const instance = pino({\n    messageKey: 'customMessageKey',\n    errorKey: 'customErrorKey',\n    customLevels: { custom: 35 }\n  }, pino.multistream([transport, { stream }]))\n\n  const error = new Error('buzz')\n  const serializedError = serializeError(error)\n  instance.custom('fizz')\n  instance.error(error)\n  await watchFileCreated(destination)\n  const result = parseLogs(await readFile(destination))\n\n  assert.deepEqual(result, [{\n    severityText: 'custom',\n    body: 'fizz',\n    attributes: {\n      pid,\n      hostname\n    }\n  }, {\n    severityText: 'error',\n    body: 'buzz',\n    attributes: {\n      pid,\n      hostname\n    },\n    error: serializedError\n  }])\n\n  assert.deepEqual(messages, [{\n    level: 35,\n    pid,\n    hostname,\n    customMessageKey: 'fizz'\n  }, {\n    level: 50,\n    pid,\n    hostname,\n    customErrorKey: serializedError,\n    customMessageKey: 'buzz'\n  }])\n})\n"
  },
  {
    "path": "test/transport-stream.test.js",
    "content": "'use strict'\n\nconst test = require('node:test')\nconst proxyquire = require('proxyquire')\nconst tspl = require('@matteo.collina/tspl')\n\ntest('should import', async (t) => {\n  const plan = tspl(t, { plan: 2 })\n  const mockRealRequire = (target) => {\n    return {\n      default: {\n        default: () => {\n          plan.equal(target, 'pino-pretty')\n          return Promise.resolve()\n        }\n      }\n    }\n  }\n  const mockRealImport = async () => {\n    await Promise.resolve()\n    throw Object.assign(new Error(), { code: 'ERR_MODULE_NOT_FOUND' })\n  }\n\n  const loadTransportStreamBuilder = proxyquire(\n    '../lib/transport-stream.js',\n    {\n      'real-require': {\n        realRequire: mockRealRequire,\n        realImport: mockRealImport\n      }\n    }\n  )\n\n  const fn = await loadTransportStreamBuilder('pino-pretty')\n\n  await fn()\n  plan.ok('returned promise resolved')\n\n  await plan\n})\n"
  },
  {
    "path": "test/types/pino-import.test-d.cts",
    "content": "import { expect } from 'tstyche'\n\nimport * as pinoStar from '../../pino.js'\nimport { type default as P, default as pino, pino as pinoNamed } from '../../pino.js'\nimport pinoCjsImport = require ('../../pino.js')\nconst pinoCjs = require('../../pino.js')\nconst { P: pinoCjsNamed } = require('pino')\n\nconst log = pino()\nexpect(log.info).type.toBe<P.LogFn>()\nexpect(log.error).type.toBe<P.LogFn>()\n\nexpect(pinoNamed()).type.toBe<pino.Logger>()\nexpect(pinoNamed()).type.toBe<P.Logger>()\nexpect(pinoStar.default()).type.toBe<pino.Logger>()\nexpect(pinoStar.pino()).type.toBe<pino.Logger>()\n// expect(pinoCjsImport.default()).type.toBe<pino.Logger>()\nexpect(pinoCjsImport.pino()).type.toBe<pino.Logger>()\nexpect(pinoCjsNamed()).type.toBe<any>()\nexpect(pinoCjs()).type.toBe<any>()\nexpect(pinoNamed.stdTimeFunctions.isoTimeNano).type.toBe<P.TimeFn>()\nexpect(pinoNamed.stdTimeFunctions.isoTimeNano()).type.toBe<string>()\n\nconst levelChangeEventListener: P.LevelChangeEventListener = (\n    lvl: P.LevelWithSilent | string,\n    val: number,\n    prevLvl: P.LevelWithSilent | string,\n    prevVal: number,\n) => {}\nexpect(levelChangeEventListener).type.toBe<P.LevelChangeEventListener>()\n"
  },
  {
    "path": "test/types/pino-multistream.test-d.ts",
    "content": "import { expect } from 'tstyche'\n\nimport { createWriteStream } from 'node:fs'\n\nimport pino, { multistream } from '../../pino.js'\n\nconst streams = [\n  { stream: process.stdout },\n  { stream: createWriteStream('') },\n  { level: 'error' as const, stream: process.stderr },\n  { level: 'fatal' as const, stream: process.stderr }\n]\n\nexpect(pino.multistream(process.stdout)).type.toBe<pino.MultiStreamRes>()\nexpect(\n  pino.multistream([createWriteStream('')])\n).type.toBe<pino.MultiStreamRes>()\nexpect(\n  pino.multistream({ level: 'error' as const, stream: process.stderr })\n).type.toBe<pino.MultiStreamRes<'error'>>()\nexpect(\n  pino.multistream([\n    { level: 'fatal' as const, stream: createWriteStream('') }\n  ])\n).type.toBe<pino.MultiStreamRes<'fatal'>>()\n\nexpect(pino.multistream(streams)).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(pino.multistream(streams, {})).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(pino.multistream(streams, { levels: { info: 30 } })).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(pino.multistream(streams, { dedupe: true })).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(pino.multistream(streams[0]).add(streams[1])).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(multistream(streams)).type.toBe<\n  pino.MultiStreamRes<'error' | 'fatal'>\n>()\nexpect(multistream(streams).clone('error')).type.toBe<\n  pino.MultiStreamRes<'error'>\n>()\n\nexpect(multistream(process.stdout)).type.toBe<pino.MultiStreamRes>()\n"
  },
  {
    "path": "test/types/pino-top-export.test-d.ts",
    "content": "import { expect } from 'tstyche'\n\nimport type { SonicBoom } from 'sonic-boom'\nimport type ThreadStream from 'thread-stream'\n\nimport {\n  destination,\n  type LevelMapping,\n  levels,\n  multistream,\n  type MultiStreamRes,\n  type SerializedError,\n  stdSerializers,\n  stdTimeFunctions,\n  transport,\n  version\n} from '../../pino.js'\n\nexpect(destination('')).type.toBe<SonicBoom>()\nexpect(levels).type.toBe<LevelMapping>()\nexpect(multistream(process.stdout)).type.toBe<MultiStreamRes>()\nexpect(stdSerializers.err({} as Error)).type.toBe<SerializedError>()\nexpect(stdTimeFunctions.isoTime()).type.toBe<string>()\nexpect(stdTimeFunctions.isoTimeNano()).type.toBe<string>()\nexpect(version).type.toBe<string>()\n\nexpect(\n  transport({\n    target: '#pino/pretty',\n    options: { some: 'options for', the: 'transport' }\n  })\n).type.toBe<ThreadStream>()\n"
  },
  {
    "path": "test/types/pino-transport.test-d.ts",
    "content": "import { expect } from 'tstyche'\n\nimport pino from '../../pino.js'\n\n// Single\nconst transport = pino.transport({\n  target: '#pino/pretty',\n  options: { some: 'options for', the: 'transport' }\n})\npino(transport)\n\nexpect(\n  pino({\n    transport: { target: 'pino-pretty' }\n  })\n).type.toBe<pino.Logger>()\n\n// Multiple\nconst transports = pino.transport({\n  targets: [\n    {\n      level: 'info',\n      target: '#pino/pretty',\n      options: { some: 'options for', the: 'transport' }\n    },\n    {\n      level: 'trace',\n      target: '#pino/file',\n      options: { destination: './test.log' }\n    }\n  ]\n})\npino(transports)\n\nexpect(\n  pino({\n    transport: {\n      targets: [\n        {\n          level: 'info',\n          target: '#pino/pretty',\n          options: { some: 'options for', the: 'transport' }\n        },\n        {\n          level: 'trace',\n          target: '#pino/file',\n          options: { destination: './test.log' }\n        }\n      ]\n    }\n  })\n).type.toBe<pino.Logger>()\n\nconst transportsWithCustomLevels = pino.transport({\n  targets: [\n    {\n      level: 'info',\n      target: '#pino/pretty',\n      options: { some: 'options for', the: 'transport' }\n    },\n    {\n      level: 'foo',\n      target: '#pino/file',\n      options: { destination: './test.log' }\n    }\n  ],\n  levels: { foo: 35 }\n})\npino(transportsWithCustomLevels)\n\nexpect(\n  pino({\n    transport: {\n      targets: [\n        {\n          level: 'info',\n          target: '#pino/pretty',\n          options: { some: 'options for', the: 'transport' }\n        },\n        {\n          level: 'trace',\n          target: '#pino/file',\n          options: { destination: './test.log' }\n        }\n      ],\n      levels: { foo: 35 }\n    }\n  })\n).type.toBe<pino.Logger>()\n\nconst transportsWithoutOptions = pino.transport({\n  targets: [\n    { target: '#pino/pretty' },\n    { target: '#pino/file' }\n  ],\n  levels: { foo: 35 }\n})\npino(transportsWithoutOptions)\n\nexpect(\n  pino({\n    transport: {\n      targets: [\n        { target: '#pino/pretty' },\n        { target: '#pino/file' }\n      ],\n      levels: { foo: 35 }\n    }\n  })\n).type.toBe<pino.Logger>()\n\nconst pipelineTransport = pino.transport({\n  pipeline: [\n    {\n      target: './my-transform.js'\n    },\n    {\n      // Use target: 'pino/file' to write to stdout\n      // without any change.\n      target: 'pino-pretty'\n    }\n  ]\n})\npino(pipelineTransport)\n\nexpect(\n  pino({\n    transport: {\n      pipeline: [\n        {\n          target: './my-transform.js'\n        },\n        {\n          // Use target: 'pino/file' to write to stdout\n          // without any change.\n          target: 'pino-pretty'\n        }\n      ]\n    }\n  })\n).type.toBe<pino.Logger>()\n\ntype TransportConfig = {\n  id: string\n}\n\n// Custom transport params\nconst customTransport = pino.transport<TransportConfig>({\n  target: 'custom',\n  options: { id: 'abc' }\n})\npino(customTransport)\n\n// Worker\npino.transport({\n  target: 'custom',\n  worker: {\n    argv: ['a', 'b'],\n    stdin: false,\n    stderr: true,\n    stdout: false,\n    autoEnd: true\n  },\n  options: { id: 'abc' }\n})\n\n// Dedupe\npino.transport({\n  targets: [],\n  dedupe: true\n})\n"
  },
  {
    "path": "test/types/pino-type-only.test-d.ts",
    "content": "import { expect } from 'tstyche'\n\nimport pino from '../../pino.js'\nimport type {\n  LevelWithSilent,\n  Logger,\n  LogFn,\n  DestinationStreamWithMetadata,\n  Level,\n  LevelOrString,\n  LevelWithSilentOrString,\n  LoggerExtras,\n  LoggerOptions\n} from '../../pino.js'\n\n// NB: can also use `import * as pino`, but that form is callable as `pino()`\n// under `esModuleInterop: false` or `pino.default()` under `esModuleInterop: true`.\nconst log = pino()\nexpect(log).type.toBeAssignableTo<LoggerExtras>()\nexpect(log).type.toBe<Logger>()\nexpect(log.info).type.toBe<LogFn>()\n\nexpect<Parameters<typeof log.isLevelEnabled>>().type.toBe<[typeof log.level]>()\n\nconst level: Level = 'debug'\nexpect(level).type.toBeAssignableTo<string>()\n\nconst levelWithSilent: LevelWithSilent = 'silent'\nexpect(levelWithSilent).type.toBeAssignableTo<string>()\n\nconst levelOrString: LevelOrString = 'myCustomLevel'\nexpect(levelOrString).type.toBeAssignableTo<string>()\nexpect(levelOrString).type.not.toBeAssignableTo<pino.Level>()\nexpect(levelOrString).type.not.toBeAssignableTo<pino.LevelWithSilent>()\nexpect(levelOrString).type.toBeAssignableTo<pino.LevelWithSilentOrString>()\n\nconst levelWithSilentOrString: LevelWithSilentOrString = 'myCustomLevel'\nexpect(levelWithSilentOrString).type.toBeAssignableTo<string>()\nexpect(levelWithSilentOrString).type.not.toBeAssignableTo<pino.Level>()\nexpect(\n  levelWithSilentOrString\n).type.not.toBeAssignableTo<pino.LevelWithSilent>()\nexpect(levelWithSilentOrString).type.toBeAssignableTo<pino.LevelOrString>()\n\nfunction createStream (): DestinationStreamWithMetadata {\n  return { write () {} }\n}\n\nconst stream = createStream()\n// Argh. TypeScript doesn't seem to narrow unless we assign the symbol like so\nconst needsMetadata: typeof pino.symbols.needsMetadataGsym =\n  pino.symbols.needsMetadataGsym\nif (stream[needsMetadata]) {\n  expect(stream.lastLevel).type.toBe<number>()\n}\n\nconst loggerOptions: LoggerOptions = {\n  browser: {\n    formatters: {\n      log (obj) {\n        return obj\n      },\n      level (label, number) {\n        return { label, number }\n      }\n    }\n  }\n}\n\nexpect(loggerOptions).type.toBe<LoggerOptions>()\n\n// Reference: https://github.com/pinojs/pino/issues/2285\nconst someConst = 'test' as const\npino().error({}, someConst)\nconst someFunc = <T extends typeof someConst>(someConst: T) => {\n  pino().error({}, someConst)\n}\n"
  },
  {
    "path": "test/types/pino.test-d.ts",
    "content": "import { expect } from 'tstyche'\n\nimport { IncomingMessage, ServerResponse } from 'node:http'\nimport { Socket } from 'node:net'\nimport { mock } from 'node:test'\n\nimport pino, { type LogFn, type LoggerOptions } from '../../pino.js'\nimport Logger = pino.Logger\n\nconst log = pino()\nconst info = log.info\nconst error = log.error\n\ninfo('hello world')\nerror('this is at error level')\n\n// primitive types\ninfo('simple string')\ninfo(true)\ninfo(42)\ninfo(3.14)\ninfo(null)\ninfo(undefined)\n\n// object types\ninfo({ a: 1, b: '2' })\ninfo(new Error())\ninfo(new Date())\ninfo([])\ninfo(new Map())\ninfo(new Set())\n\n// placeholder messages\ninfo('Hello %s', 'world')\ninfo('The answer is %d', 42)\ninfo('The object is %o', { a: 1, b: '2' })\ninfo('The json is %j', { a: 1, b: '2' })\ninfo('The object is %O', { a: 1, b: '2' })\ninfo('The answer is %d and the question is %s with %o', 42, 'unknown', {\n  correct: 'order'\n})\ninfo('Missing placeholder is fine %s')\n\n// %s placeholder supports all primitive types\ninfo('Boolean %s', true)\ninfo('Boolean %s', false)\ninfo('Number %s', 123)\ninfo('Number %s', 3.14)\ninfo('BigInt %s', BigInt(123))\ninfo('Null %s', null)\ninfo('Undefined %s', undefined)\ninfo('Symbol %s', Symbol('test'))\ninfo('String %s', 'hello')\n\n// %s placeholder with multiple primitives\ninfo('Multiple primitives %s %s %s', true, 42, 'world')\ninfo(\n  'All primitive types %s %s %s %s %s %s %s',\n  'string',\n  123,\n  true,\n  BigInt(123),\n  null,\n  undefined,\n  Symbol('test')\n)\ndeclare const errorOrString: string | Error\ninfo(errorOrString)\n\n// %o placeholder supports primitives too (except undefined)\ninfo('Boolean %o', true)\ninfo('Boolean %o', false)\ninfo('Number %o', 123)\ninfo('Number %o', 3.14)\ninfo('BigInt %o', BigInt(123))\ninfo('Null %o', null)\ninfo('Symbol %o', Symbol('test'))\ninfo('String %o', 'hello')\n\n// placeholder messages type errors\nexpect(info).type.not.toBeCallableWith('The answer is %d', 'not a number')\nexpect(info).type.not.toBeCallableWith(\n  'The answer is %d and the question is %s with %o',\n  'unknown',\n  { incorrect: 'order' },\n  42\n)\nexpect(info).type.not.toBeCallableWith(\n  'Extra message %s',\n  'after placeholder',\n  'not allowed'\n)\n\n// object types with messages\ninfo({ obj: 42 }, 'hello world')\ninfo({ obj: 42, b: 2 }, 'hello world')\ninfo({ obj: { aa: 'bbb' } }, 'another')\ninfo({ a: 1, b: '2' }, 'hello world with %s', 'extra data')\n\n// Extra message after placeholder\nexpect(info).type.not.toBeCallableWith(\n  { a: 1, b: '2' },\n  'hello world with %d',\n  2,\n  'extra'\n)\n\n// metadata with messages type passes, because of custom toString method\n// We can't detect if the object has a custom toString method that returns a string\ninfo({ a: 1, b: '2' }, 'hello world with %s', {})\n\n// metadata after message\nexpect(info).type.not.toBeCallableWith('message', { a: 1, b: '2' })\n\n// multiple strings without placeholder\nexpect(info).type.not.toBeCallableWith('string1', 'string2')\nexpect(info).type.not.toBeCallableWith('string1', 'string2', 'string3')\n\nsetImmediate(info, 'after setImmediate')\nerror(new Error('an error'))\n\nconst writeSym = pino.symbols.writeSym\n\nconst testUniqSymbol = {\n  [pino.symbols.needsMetadataGsym]: true\n}[pino.symbols.needsMetadataGsym]\n\nconst log2: pino.Logger = pino({\n  name: 'myapp',\n  safe: true,\n  serializers: {\n    req: pino.stdSerializers.req,\n    res: pino.stdSerializers.res,\n    err: pino.stdSerializers.err\n  }\n})\n\npino({\n  write (o) {}\n})\n\npino({\n  mixin () {\n    return { customName: 'unknown', customId: 111 }\n  }\n})\n\npino({\n  mixin: () => ({ customName: 'unknown', customId: 111 })\n})\n\npino({\n  mixin: (context: object) => ({ customName: 'unknown', customId: 111 })\n})\n\npino({\n  mixin: (context: object, level: number) => ({\n    customName: 'unknown',\n    customId: 111\n  })\n})\n\npino({\n  redact: { paths: [], censor: 'SECRET' }\n})\n\npino({\n  redact: { paths: [], censor: () => 'SECRET' }\n})\n\npino({\n  redact: { paths: [], censor: (value) => value }\n})\n\npino({\n  redact: { paths: [], censor: (value, path) => path.join() }\n})\n\npino({\n  redact: {\n    paths: [],\n    censor: (value): string => 'SECRET'\n  }\n})\n\nexpect(pino).type.not.toBeCallableWith({\n  redact: { paths: [], censor: (value: string) => value }\n})\n\npino({\n  depthLimit: 1\n})\n\npino({\n  edgeLimit: 1\n})\n\npino({\n  browser: {\n    write (o) {}\n  }\n})\n\npino({\n  browser: {\n    write: {\n      info (o) {},\n      error (o) {}\n    },\n    serialize: true,\n    asObject: true,\n    transmit: {\n      level: 'fatal',\n      send: (level, logEvent) => {\n        level\n        logEvent.bindings\n        logEvent.level\n        logEvent.ts\n        logEvent.messages\n      }\n    },\n    disabled: false\n  }\n})\n\npino({\n  browser: {\n    asObjectBindingsOnly: true\n  }\n})\n\npino({}, undefined)\n\npino({ base: null })\nif ('pino' in log) console.log(`pino version: ${log.pino}`)\n\nexpect(log.flush()).type.toBe<void>()\nlog.flush((err?: Error) => undefined)\nlog.child({ a: 'property' }).info('hello child!')\nlog.level = 'error'\nlog.info('nope')\nconst child = log.child({ foo: 'bar' })\nchild.info('nope again')\nchild.level = 'info'\nchild.info('hooray')\nlog.info('nope nope nope')\nlog.child({ foo: 'bar' }, { level: 'debug' }).debug('debug!')\nchild.bindings()\nconst customSerializers = {\n  test () {\n    return 'this is my serializer'\n  }\n}\npino()\n  .child({}, { serializers: customSerializers })\n  .info({ test: 'should not show up' })\nconst child2 = log.child({ father: true })\nconst childChild = child2.child({ baby: true })\nconst childRedacted = pino().child({}, { redact: ['path'] })\nchildRedacted.info({\n  msg: 'logged with redacted properties',\n  path: 'Not shown'\n})\nconst childAnotherRedacted = pino().child(\n  {},\n  {\n    redact: {\n      paths: ['anotherPath'],\n      censor: 'Not the log you\\re looking for'\n    }\n  }\n)\nchildAnotherRedacted.info({\n  msg: 'another logged with redacted properties',\n  anotherPath: 'Not shown'\n})\n\nlog.level = 'info'\nif (log.levelVal === 30) {\n  console.log('logger level is `info`')\n}\n\nconst listener = (lvl: any, val: any, prevLvl: any, prevVal: any) => {\n  console.log(lvl, val, prevLvl, prevVal)\n}\nlog.on('level-change', (lvl, val, prevLvl, prevVal, logger) => {\n  console.log(lvl, val, prevLvl, prevVal)\n})\nlog.level = 'trace'\nlog.removeListener('level-change', listener)\nlog.level = 'info'\n\npino.levels.values.error === 50\npino.levels.labels[50] === 'error'\n\nconst logstderr: pino.Logger = pino(process.stderr)\nlogstderr.error('on stderr instead of stdout')\n\nlog.useLevelLabels = true\nlog.info('lol')\nlog.level === 'info'\nconst isEnabled: boolean = log.isLevelEnabled('info')\n\nconst redacted = pino({\n  redact: ['path']\n})\n\nredacted.info({\n  msg: 'logged with redacted properties',\n  path: 'Not shown'\n})\n\nconst anotherRedacted = pino({\n  redact: {\n    paths: ['anotherPath'],\n    censor: 'Not the log you\\re looking for'\n  }\n})\n\nanotherRedacted.info({\n  msg: 'another logged with redacted properties',\n  anotherPath: 'Not shown'\n})\n\nconst withTimeFn = pino({\n  timestamp: pino.stdTimeFunctions.isoTime\n})\n\nconst withRFC3339TimeFn = pino({\n  timestamp: pino.stdTimeFunctions.isoTimeNano\n})\n\nconst withNestedKey = pino({\n  nestedKey: 'payload'\n})\n\nconst withHooks = pino({\n  hooks: {\n    logMethod (args, method, level) {\n      expect(this).type.toBe<pino.Logger>()\n      return method.apply(this, args)\n    },\n    streamWrite (s) {\n      expect(s).type.toBe<string>()\n      return s.replaceAll('secret-key', 'xxx')\n    }\n  }\n})\n\n// Properties/types imported from pino-std-serializers\nconst wrappedErrSerializer = pino.stdSerializers.wrapErrorSerializer(\n  (err: pino.SerializedError) => {\n    return { ...err, newProp: 'foo' }\n  }\n)\nconst wrappedReqSerializer = pino.stdSerializers.wrapRequestSerializer(\n  (req: pino.SerializedRequest) => {\n    return { ...req, newProp: 'foo' }\n  }\n)\nconst wrappedResSerializer = pino.stdSerializers.wrapResponseSerializer(\n  (res: pino.SerializedResponse) => {\n    return { ...res, newProp: 'foo' }\n  }\n)\n\nconst socket = new Socket()\nconst incomingMessage = new IncomingMessage(socket)\nconst serverResponse = new ServerResponse(incomingMessage)\n\nconst mappedHttpRequest: { req: pino.SerializedRequest } =\n  pino.stdSerializers.mapHttpRequest(incomingMessage)\nconst mappedHttpResponse: { res: pino.SerializedResponse } =\n  pino.stdSerializers.mapHttpResponse(serverResponse)\n\nconst serializedErr: pino.SerializedError = pino.stdSerializers.err(\n  new Error()\n)\nconst serializedReq: pino.SerializedRequest =\n  pino.stdSerializers.req(incomingMessage)\nconst serializedRes: pino.SerializedResponse =\n  pino.stdSerializers.res(serverResponse)\n\n/**\n * Destination static method\n */\nconst destinationViaDefaultArgs = pino.destination()\nconst destinationViaStrFileDescriptor = pino.destination('/log/path')\nconst destinationViaNumFileDescriptor = pino.destination(2)\nconst destinationViaStream = pino.destination(process.stdout)\nconst destinationViaOptionsObject = pino.destination({\n  dest: '/log/path',\n  sync: false\n})\n\npino(destinationViaDefaultArgs)\npino({ name: 'my-logger' }, destinationViaDefaultArgs)\npino(destinationViaStrFileDescriptor)\npino({ name: 'my-logger' }, destinationViaStrFileDescriptor)\npino(destinationViaNumFileDescriptor)\npino({ name: 'my-logger' }, destinationViaNumFileDescriptor)\npino(destinationViaStream)\npino({ name: 'my-logger' }, destinationViaStream)\npino(destinationViaOptionsObject)\npino({ name: 'my-logger' }, destinationViaOptionsObject)\n\ntry {\n  throw new Error('Some error')\n} catch (err) {\n  log.error(err)\n}\n\ninterface StrictShape {\n  activity: string;\n  err?: unknown;\n}\n\ninfo<StrictShape>({\n  activity: 'Required property'\n})\n\nconst logLine: pino.LogDescriptor = {\n  level: 20,\n  msg: 'A log message',\n  time: new Date().getTime(),\n  aCustomProperty: true\n}\n\ninterface CustomLogger extends pino.Logger {\n  customMethod(msg: string, ...args: unknown[]): void;\n}\n\nconst serializerFunc: pino.SerializerFn = () => {}\nconst writeFunc: pino.WriteFn = () => {}\n\ninterface CustomBaseLogger extends pino.BaseLogger {\n  child(): CustomBaseLogger;\n}\n\nconst customBaseLogger: CustomBaseLogger = {\n  level: 'info',\n  fatal () {},\n  error () {},\n  warn () {},\n  info () {},\n  debug () {},\n  trace () {},\n  silent () {},\n  child () {\n    return this\n  },\n  msgPrefix: 'prefix'\n}\n\n// custom levels\nconst log3 = pino({ customLevels: { myLevel: 100 } })\nexpect(log3).type.not.toHaveProperty('log')\nlog3.level = 'myLevel'\nlog3.myLevel('')\nlog3.child({}).myLevel('')\n\nlog3.on('level-change', (lvl, val, prevLvl, prevVal, instance) => {\n  instance.myLevel('foo')\n})\n\nconst clog3 = log3.child({}, { customLevels: { childLevel: 120 } })\n// child inherit parent\nclog3.myLevel('')\n// child itself\nclog3.childLevel('')\nconst cclog3 = clog3.child({}, { customLevels: { childLevel2: 130 } })\n// child inherit root\ncclog3.myLevel('')\n// child inherit parent\ncclog3.childLevel('')\n// child itself\ncclog3.childLevel2('')\n\nconst ccclog3 = clog3.child({})\nexpect(ccclog3).type.not.toHaveProperty('nonLevel')\n\nconst withChildCallback = pino({\n  onChild: (child: Logger) => {}\n})\nwithChildCallback.onChild = (child: Logger) => {}\n\npino({\n  crlf: true\n})\n\nconst customLevels = { foo: 99, bar: 42 }\n\nconst customLevelLogger = pino({ customLevels })\n\ntype CustomLevelLogger = typeof customLevelLogger\ntype CustomLevelLoggerLevels = pino.Level | keyof typeof customLevels\n\nconst fn = (logger: Pick<CustomLevelLogger, CustomLevelLoggerLevels>) => {}\n\nconst customLevelChildLogger = customLevelLogger.child({ name: 'child' })\n\nfn(customLevelChildLogger) // missing foo typing\n\n// unknown option\nexpect(pino).type.not.toBeCallableWith({\n  hello: 'world'\n})\n\n// unknown option\nexpect(pino).type.not.toBeCallableWith({\n  hello: 'world',\n  customLevels: {\n    log: 30\n  }\n})\n\nfunction dangerous () {\n  throw Error('foo')\n}\n\ntry {\n  dangerous()\n} catch (err) {\n  log.error(err)\n}\n\ntry {\n  dangerous()\n} catch (err) {\n  log.error({ err })\n}\n\nconst bLogger = pino({\n  customLevels: {\n    log: 5\n  },\n  level: 'log',\n  transport: {\n    target: 'pino-pretty',\n    options: {\n      colorize: true\n    }\n  }\n})\n\n// Test that we can properly extract parameters from the log fn type\ntype LogParam = Parameters<LogFn>\nconst [param1, param2, param3, param4]: LogParam = [\n  { multiple: 'params' },\n  'should',\n  'be',\n  'accepted'\n]\n\nexpect(param1).type.toBe<unknown>()\nexpect(param2).type.toBe<string>()\nexpect(param3).type.toBe<unknown>()\nexpect(param4).type.toBe<unknown>()\n\nconst logger = mock.fn<LogFn>()\nlogger.mock.calls[0].arguments[1]?.includes('I should be able to get params')\n\nconst hooks: LoggerOptions['hooks'] = {\n  logMethod (this, parameters, method) {\n    if (parameters.length >= 2) {\n      const [parameter1, parameter2, ...remainingParameters] = parameters\n      if (typeof parameter1 === 'string') {\n        return method.apply(this, [\n          parameter2,\n          parameter1,\n          ...remainingParameters\n        ])\n      }\n      return method.apply(this, [parameter2])\n    }\n\n    return method.apply(this, parameters)\n  }\n}\n\nexpect(\n  pino({\n    customLevels: {\n      log: 5\n    },\n    level: 'log',\n    transport: {\n      target: 'pino-pretty',\n      options: {\n        colorize: true\n      }\n    }\n  })\n).type.toBe<Logger<'log'>>()\n\nconst parentLogger1 = pino(\n  {\n    customLevels: { myLevel: 90 },\n    onChild: (child) => {\n      const a = child.myLevel\n    }\n  },\n  process.stdout\n)\nparentLogger1.onChild = (child) => {\n  child.myLevel('')\n}\n\nconst childLogger1 = parentLogger1.child({})\nchildLogger1.myLevel('')\nexpect(childLogger1).type.not.toHaveProperty('doesntExist')\n\nconst parentLogger2 = pino({}, process.stdin)\nparentLogger2.onChild = (child) => {\n  expect(child).type.not.toHaveProperty('doesntExist')\n}\n\nconst childLogger2 = parentLogger2.child({})\nexpect(childLogger2).type.not.toHaveProperty('doesntExist')\n\npino(\n  {\n    onChild: (child) => {\n      expect(child).type.not.toHaveProperty('doesntExist')\n    }\n  },\n  process.stdout\n)\n\nconst pinoWithoutLevelsSorting = pino({})\nconst pinoWithDescSortingLevels = pino({ levelComparison: 'DESC' })\nconst pinoWithAscSortingLevels = pino({ levelComparison: 'ASC' })\nconst pinoWithCustomSortingLevels = pino({ levelComparison: () => false })\n// with wrong level comparison direction\nexpect(pino).type.not.toBeCallableWith({ levelComparison: 'SOME' })\n// with wrong level comparison type\nexpect(pino).type.not.toBeCallableWith({ levelComparison: 123 })\n// with wrong custom level comparison return type\nexpect(pino).type.not.toBeCallableWith({ levelComparison: () => null })\nexpect(pino).type.not.toBeCallableWith({ levelComparison: () => 1 })\nexpect(pino).type.not.toBeCallableWith({ levelComparison: () => 'string' })\n\nconst customLevelsOnlyOpts = {\n  useOnlyCustomLevels: true,\n  customLevels: {\n    customDebug: 10,\n    info: 20, // to make sure the default names are also available for override\n    customNetwork: 30,\n    customError: 40\n  },\n  level: 'customDebug'\n} satisfies LoggerOptions\n\nconst loggerWithCustomLevelOnly = pino(customLevelsOnlyOpts)\nloggerWithCustomLevelOnly.customDebug('test3')\nloggerWithCustomLevelOnly.info('test4')\nloggerWithCustomLevelOnly.customError('test5')\nloggerWithCustomLevelOnly.customNetwork('test6')\n\nexpect(loggerWithCustomLevelOnly.fatal).type.toBe<never>()\nexpect(loggerWithCustomLevelOnly.error).type.toBe<never>()\nexpect(loggerWithCustomLevelOnly.warn).type.toBe<never>()\nexpect(loggerWithCustomLevelOnly.debug).type.toBe<never>()\nexpect(loggerWithCustomLevelOnly.trace).type.toBe<never>()\n\n// Module extension\ndeclare module '../../' {\n  interface LogFnFields {\n    bannedField?: never;\n    typeCheckedField?: string;\n  }\n}\n\ninfo({ typeCheckedField: 'bar' })\nexpect(info).type.not.toBeCallableWith({ bannedField: 'bar' })\nexpect(info).type.not.toBeCallableWith({ typeCheckedField: 123 })\nconst someGenericFunction = <T extends string | number | symbol = never>(\n  arg: Record<T, unknown>\n) => {\n  info(arg)\n}\n"
  },
  {
    "path": "test/types/pino.ts",
    "content": "import { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport pinoPretty from 'pino-pretty'\n\n// Test both default (\"Pino\") and named (\"pino\") imports.\nimport Pino, {\n  type LoggerOptions,\n  type StreamEntry,\n  pino,\n  multistream,\n  transport\n} from '../../pino.js'\n\nconst destination = join(\n  tmpdir(),\n  '_' + Math.random().toString(36).slice(2, 9)\n)\n\n// Single\nconst transport1 = transport({\n  target: 'pino-pretty',\n  options: { some: 'options for', the: 'transport' }\n})\nconst logger = pino(transport1)\nlogger.setBindings({ some: 'bindings' })\nlogger.info('test2')\nlogger.flush()\nconst loggerDefault = Pino(transport1)\nloggerDefault.setBindings({ some: 'bindings' })\nloggerDefault.info('test2')\nloggerDefault.flush()\n\nconst transport2 = transport({\n  target: 'pino-pretty'\n})\nconst logger2 = pino(transport2)\nlogger2.info('test2')\nconst logger2Default = Pino(transport2)\nlogger2Default.info('test2')\n\n// Multiple\n\nconst transports = transport({\n  targets: [\n    {\n      level: 'info',\n      target: 'pino-pretty',\n      options: { some: 'options for', the: 'transport' }\n    },\n    {\n      level: 'trace',\n      target: 'pino/file',\n      options: { destination }\n    }\n  ]\n})\nconst loggerMulti = pino(transports)\nloggerMulti.info('test2')\n\n// custom levels\n\nconst customLevels = {\n  customDebug: 1,\n  info: 2,\n  customNetwork: 3,\n  customError: 4\n}\n\ntype CustomLevels = keyof typeof customLevels\n\nconst pinoOpts = {\n  useOnlyCustomLevels: true,\n  customLevels,\n  level: 'customDebug'\n} satisfies LoggerOptions\n\nconst multistreamOpts = {\n  dedupe: true,\n  levels: customLevels\n}\n\nconst streams: StreamEntry<CustomLevels>[] = [\n  { level: 'customDebug', stream: pinoPretty() },\n  { level: 'info', stream: pinoPretty() },\n  { level: 'customNetwork', stream: pinoPretty() },\n  { level: 'customError', stream: pinoPretty() }\n]\n\nconst loggerCustomLevel = pino(pinoOpts, multistream(streams, multistreamOpts))\nloggerCustomLevel.customDebug('test3')\nloggerCustomLevel.info('test4')\nloggerCustomLevel.customError('test5')\nloggerCustomLevel.customNetwork('test6')\nconst loggerCustomLevelDefault = Pino(pinoOpts, multistream(streams, multistreamOpts))\nloggerCustomLevelDefault.customDebug('test3')\nloggerCustomLevelDefault.info('test4')\nloggerCustomLevelDefault.customError('test5')\nloggerCustomLevelDefault.customNetwork('test6')\n"
  },
  {
    "path": "test/types/tsconfig.json",
    "content": "{\n  \"extends\": \"fastify-tsconfig\",\n  \"compilerOptions\": {\n    \"noEmit\": true,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"types\": []\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"lib\": [ \"es2015\", \"dom\" ],\n    \"module\": \"commonjs\",\n    \"noEmit\": true,\n    \"strict\": true,\n    \"esModuleInterop\": true\n  },\n  \"exclude\": [\n    \"./test/types/**/*\",\n    \"./*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "tstyche.config.json",
    "content": "{\n\t\"$schema\": \"https://tstyche.org/schemas/config.json\",\n\t\"testFileMatch\": [\"test/types/*.{cts,ts}\"]\n}\n"
  }
]