├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .nycrc.yml ├── .taprc ├── LICENSE ├── README.md ├── benchmarks ├── basic.bench.js ├── deep-object.bench.js ├── object.bench.js ├── runbench.js └── usage.txt ├── debug.js ├── example ├── app.js ├── bin │ ├── www │ └── www-programmatic ├── package.json ├── public │ └── stylesheets │ │ └── style.css ├── routes │ ├── index.js │ └── users.js └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade ├── index.js ├── package.json ├── scripts └── npmi.js └── test ├── fixtures ├── line-numbers.js ├── object-override.js ├── strict-mode.js └── trailing-comment.js └── index.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | open-pull-requests-limit: 10 8 | 9 | - package-ecosystem: "npm" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | open-pull-requests-limit: 10 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'docs/**' 7 | - '*.md' 8 | pull_request: 9 | paths-ignore: 10 | - 'docs/**' 11 | - '*.md' 12 | 13 | jobs: 14 | build: 15 | name: ${{ matrix.node-version }} ${{ matrix.os }} 16 | runs-on: ${{ matrix.os }} 17 | permissions: 18 | contents: read 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | os: [ubuntu-latest] 23 | node-version: [18, 20, 22] 24 | debug: [2, 3, 4] 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v3 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | 34 | - name: Install dependencies 35 | run: npm i 36 | - name: Install debug@${{ matrix.debug}} 37 | run: npm i --no-save debug@${{ matrix.debug }} 38 | 39 | - name: Run Tests 40 | run: npm run ci 41 | 42 | automerge: 43 | needs: build 44 | runs-on: ubuntu-latest 45 | permissions: 46 | pull-requests: write 47 | contents: write 48 | steps: 49 | - uses: fastify/github-action-merge-dependabot@v3 50 | with: 51 | github-token: ${{ secrets.GITHUB_TOKEN }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | coverage/ 4 | .nyc_output/ 5 | .tap/ 6 | tmp/ 7 | npm-debug.log* 8 | .DS_Store 9 | .idea 10 | .vscode 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | coverage/ 3 | .nyc_output/ 4 | .tap/ 5 | scripts/ 6 | .github/ 7 | test/ -------------------------------------------------------------------------------- /.nycrc.yml: -------------------------------------------------------------------------------- 1 | use-spawn-wrap: true 2 | include: [index.js, debug.js] 3 | reporter: [text, lcov, html] 4 | check-coverage: true 5 | statements: 100 6 | branches: 97 7 | functions: 100 8 | lines: 100 9 | -------------------------------------------------------------------------------- /.taprc: -------------------------------------------------------------------------------- 1 | timeout: 480 2 | reporter: terse 3 | include: [test/*.js] 4 | disable-coverage: true 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 David Mark Clements; 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pino-debug [![stability][0]][1] 2 | [![npm version][2]][3] [![build status][4]][5] [![test coverage][6]][7] 3 | [![downloads][8]][9] [![dependencies freshness][14]][15] [![js-standard-style][10]][11] 4 | 5 | High performance debug logging. 6 | 7 | Seamlessly integrates the [`debug`][12] module with the high performance [`pino`][13] 8 | logger so you can turn on debug logs in production scenarios 9 | with minimum overhead. 10 | 11 | * Up to 10x faster than using [`debug`][12] (20x in extreme mode!) 12 | * JSON output with more detail (`pino`/`bunyan`/`bole` format) 13 | * Safe with circular references ([`debug`][12] isn't) 14 | * No need to replace any `debug` logging calls 15 | * Associate namespaces with log levels 16 | * Compatible with the entire pino ecosystem 17 | 18 | ## Installation 19 | ```sh 20 | $ npm install --save pino-debug 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Preload 26 | 27 | If all you want is fast JSON logging to STDOUT 28 | 29 | ```sh 30 | $ DEBUG=* node -r pino-debug app.js 31 | ``` 32 | 33 | Namespaces are enabled the usual way, via the `DEBUG` 34 | environment variable. 35 | 36 | The namespace is also included in the log output, in the `ns` key. 37 | 38 | Here's a sample log when the above is applied to a generic express app: 39 | 40 | ```json 41 | {"pid":8784,"hostname":"Davids-MacBook-Pro.local","level":20,"time":1480277659273,"msg":"skip empty body","ns":"body-parser:json","v":1} 42 | ``` 43 | 44 | ### Programmatic 45 | 46 | For fine grained control over output stream, and mappings 47 | between [`debug`][12] namespaces and [`pino`][13] logger levels, 48 | supply a [`pino`][13] instance and an optional options object with 49 | a `map` property containing mappings. 50 | 51 | **NOTE**: `pino-debug` **must** be required at the entry point of your node process, 52 | before any other modules have been loaded 53 | 54 | Again this example assumes a generic `express` app: 55 | 56 | ```js 57 | const pinoDebug = require('pino-debug') 58 | const logger = require('pino')({level: process.env.LEVEL || 'info'}, process.stderr); 59 | pinoDebug(logger, { 60 | auto: true, // default 61 | map: { 62 | 'example:server': 'info', 63 | 'express:router': 'debug', 64 | '*': 'trace' // everything else - trace 65 | } 66 | }) 67 | ``` 68 | 69 | The `auto` option turns on any namespaces listed in the `map` object 70 | (so we don't have to use the `DEBUG` environment variable to turn them on). 71 | 72 | ## API 73 | 74 | **NOTE**: `pino-debug` can only be called **once**. 75 | 76 | ### pinoDebug(pinoInstance) => undefined 77 | 78 | Call `pino-debug` with a [`pino`][13] logger instance only and any debug namespaces 79 | enabled via `DEBUG` or `debug.enable` will be logged with the level 20 (`'debug'`). 80 | 81 | Remember, if you want to see the messages you need to set the [`pino`][13] logger instance 82 | logging level to `'debug'`. 83 | 84 | ### pinoDebug() => undefined 85 | 86 | Call `pino-debug` without arguments and a default [`pino`][13] instance will be created with 87 | the logging level set to 20 (`'debug'` level). 88 | 89 | Any debug namespaces enabled via `DEBUG` or `debug.enable` will be logged 90 | with the level 20 (`'debug'`). 91 | 92 | ### pinoDebug(pinoInstance, opts) => undefined 93 | 94 | This is the recommended usage. Call `pino-debug` with a [`pino`][13] logger instance, 95 | and an `opts` object containining `map` property. 96 | 97 | #### `opts.map` `{'debug-namespace: 'pino-loglevel-label'}` 98 | 99 | The keys of the `map` property correspond to the same namespaces that can be 100 | set on the `DEBUG` environment variable: 101 | 102 | ```js 103 | pinoDebug(pinoInstance, { 104 | map: { 105 | 'my-app': 'info', 106 | 'some-dep:*': 'debug', 107 | '*': 'trace' 108 | } 109 | }) 110 | ``` 111 | 112 | #### `opts.auto` `[true] | false` 113 | 114 | If `true` (default) any debug namespaces found in the keys of `opts.map` will be 115 | enabled. 116 | 117 | Additionally, any debug namespaces enabled via `DEBUG` or `debug.enable` 118 | will be logged with the level 20 (`'debug'`). 119 | 120 | If `false`, any namespaces that appear in `opts.map` **and** are enabled via 121 | `DEBUG` or `debug.enable` will be logged to with the corresponding log level, 122 | (as specified in the `opts.map`). Any not specified in `opts.map`, but which 123 | are enabled via `DEBUG` or `debug.enable` will be logged with the level 20 (`'debug'`). 124 | 125 | #### `opts.skip` `Array` 126 | 127 | Equivalent of prefixing a namespace with dash (`-`) when specifying 128 | `DEBUG` namespaces. Any namespaces specified will not be logged. 129 | 130 | ## Benchmarks 131 | 132 | ```sh 133 | $ npm run bench 134 | ``` 135 | 136 | ```sh 137 | ========== 138 | basic averages 139 | Pino average: 249 140 | Debug average: 395 141 | PinoDebug average: 244 142 | PinoExtremeDebug average: 119 143 | ========== 144 | ========== 145 | object averages 146 | PinoObj average: 262 147 | DebugObj average: 2448 148 | PinoDebugObj average: 256 149 | PinoExtremeDebugDeepObj average: 126 150 | ========== 151 | ========== 152 | deepobject averages 153 | PinoDeepObj average: 4809 154 | DebugDeepObj average: 30083 155 | PinoDebugDeepObj average: 4793 156 | PinoExtremeDebugDeepObj average: 4810 157 | ========== 158 | ``` 159 | 160 | ## Example Folder 161 | 162 | The example folder has a generic `express` app, with some additions. 163 | 164 | The `package.json` file has the following `scripts`: 165 | 166 | ``` 167 | "start": "node ./bin/www", 168 | "start-preload": "DEBUG=* node -r ../ ./bin/www", 169 | "start-programmatic": "./bin/www-programmatic", 170 | "start-programmatic-debug": "LEVEL=debug ./bin/www-programmatic", 171 | "start-programmatic-trace": "LEVEL=trace ./bin/www-programmatic" 172 | ``` 173 | 174 | The `start-preload` script demonstrates preload usage. It set's 175 | the `DEBUG` environment variable to log everything, 176 | and then uses the `-r` flag to load `pino-debug` (relatively referenced). 177 | 178 | The three scripts beginning `start-programmatic` all use a different 179 | entry point where `pino-debug` has been required and instantiated with 180 | a [`pino`][13] instance and the mappings (as shown in usage examples). 181 | 182 | ## License 183 | [MIT](https://tldrlegal.com/license/mit-license) 184 | 185 | ## Acknowledgements 186 | Sponsored by [nearForm](http://tldrlegal.com/license/mit-license) 187 | 188 | [0]: https://img.shields.io/badge/stability-stable-green.svg?style=flat-square 189 | [1]: https://nodejs.org/api/documentation.html#documentation_stability_index 190 | [2]: https://img.shields.io/npm/v/pino-debug.svg?style=flat-square 191 | [3]: https://npmjs.org/package/pino-debug 192 | [4]: https://img.shields.io/github/actions/workflow/status/pinojs/pino-debug/ci.yml?style=flat-square 193 | [5]: https://github.com/pinojs/pino-debug/actions?query=workflow%3ACI+branch%3Amaster 194 | [6]: https://img.shields.io/codecov/c/github/pinojs/pino-debug/master.svg?style=flat-square 195 | [7]: https://codecov.io/github/pinojs/pino-debug 196 | [8]: http://img.shields.io/npm/dm/pino-debug.svg?style=flat-square 197 | [9]: https://npmjs.org/package/pino-debug 198 | [10]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 199 | [11]: https://github.com/feross/standard 200 | [12]: https://npm.im/debug 201 | [13]: https://npm.im/pino 202 | [14]: https://img.shields.io/librariesio/release/npm/pino-debug?style=flat-square 203 | [15]: https://libraries.io/npm/pino-debug 204 | -------------------------------------------------------------------------------- /benchmarks/basic.bench.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const wrap = require('module').wrap 3 | const bench = require('fastbench') 4 | let pino = require('pino') 5 | const fs = require('fs') 6 | const dest = process.platform === 'win32' ? fs.createWriteStream('\\\\.\\NUL') : fs.createWriteStream('/dev/null') 7 | const plog = pino(dest) 8 | 9 | process.env.DEBUG = 'dlog' 10 | const dlog = require('debug')('dlog') 11 | dlog.log = function (s) { dest.write(s) } 12 | 13 | delete require.cache[require.resolve('debug')] 14 | delete require.cache[require.resolve('debug/src/debug.js')] 15 | delete require.cache[require.resolve('debug/src/node')] 16 | 17 | delete require.cache[require.resolve('pino')] 18 | pino = require('pino') 19 | require('../')(pino({ level: 'debug' }, dest)) 20 | const pdlog = require('debug')('dlog') 21 | 22 | delete require.cache[require.resolve('debug')] 23 | delete require.cache[require.resolve('debug/src/debug.js')] 24 | delete require.cache[require.resolve('debug/src/node')] 25 | delete require.cache[require.resolve('../')] 26 | delete require.cache[require.resolve('../debug')] 27 | require('module').wrap = wrap 28 | 29 | delete require.cache[require.resolve('pino')] 30 | pino = require('pino') 31 | require('../')(pino({ extreme: true, level: 'debug' }, dest)) 32 | const pedlog = require('debug')('dlog') 33 | 34 | const max = 10 35 | const run = bench([ 36 | function benchPino (cb) { 37 | for (let i = 0; i < max; i++) { 38 | plog.info('hello world') 39 | } 40 | setImmediate(cb) 41 | }, 42 | function benchDebug (cb) { 43 | for (let i = 0; i < max; i++) { 44 | dlog('hello world') 45 | } 46 | setImmediate(cb) 47 | }, 48 | function benchPinoDebug (cb) { 49 | for (let i = 0; i < max; i++) { 50 | pdlog('hello world') 51 | } 52 | setImmediate(cb) 53 | }, 54 | function benchPinoExtremeDebug (cb) { 55 | for (let i = 0; i < max; i++) { 56 | pedlog('hello world') 57 | } 58 | setImmediate(cb) 59 | } 60 | ], 10000) 61 | 62 | run(run) 63 | -------------------------------------------------------------------------------- /benchmarks/deep-object.bench.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const wrap = require('module').wrap 3 | const bench = require('fastbench') 4 | let pino = require('pino') 5 | const fs = require('fs') 6 | const dest = process.platform === 'win32' ? fs.createWriteStream('\\\\.\\NUL') : fs.createWriteStream('/dev/null') 7 | const plog = pino(dest) 8 | 9 | process.env.DEBUG = 'dlog' 10 | const dlog = require('debug')('dlog') 11 | dlog.log = function (s) { dest.write(s) } 12 | 13 | delete require.cache[require.resolve('debug')] 14 | delete require.cache[require.resolve('debug/src/debug.js')] 15 | delete require.cache[require.resolve('debug/src/node')] 16 | 17 | delete require.cache[require.resolve('pino')] 18 | pino = require('pino') 19 | require('../')(pino({ level: 'debug' }, dest)) 20 | const pdlog = require('debug')('dlog') 21 | 22 | delete require.cache[require.resolve('debug')] 23 | delete require.cache[require.resolve('debug/src/debug.js')] 24 | delete require.cache[require.resolve('debug/src/node')] 25 | delete require.cache[require.resolve('../')] 26 | delete require.cache[require.resolve('../debug')] 27 | require('module').wrap = wrap 28 | 29 | delete require.cache[require.resolve('pino')] 30 | pino = require('pino') 31 | require('../')(pino({ extreme: true, level: 'debug' }, dest)) 32 | const pedlog = require('debug')('dlog') 33 | 34 | const deep = require('../package.json') 35 | deep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep))) 36 | deep.deep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep))) 37 | deep.deep.deep.deep = Object.assign({}, JSON.parse(JSON.stringify(deep))) 38 | 39 | const max = 10 40 | 41 | const run = bench([ 42 | function benchPinoDeepObj (cb) { 43 | for (let i = 0; i < max; i++) { 44 | plog.info(deep) 45 | } 46 | setImmediate(cb) 47 | }, 48 | function benchDebugDeepObj (cb) { 49 | for (let i = 0; i < max; i++) { 50 | dlog(deep) 51 | } 52 | setImmediate(cb) 53 | }, 54 | function benchPinoDebugDeepObj (cb) { 55 | for (let i = 0; i < max; i++) { 56 | pdlog(deep) 57 | } 58 | setImmediate(cb) 59 | }, 60 | function benchPinoExtremeDebugDeepObj (cb) { 61 | for (let i = 0; i < max; i++) { 62 | pedlog(deep) 63 | } 64 | setImmediate(cb) 65 | } 66 | ], 10000) 67 | 68 | run(run) 69 | -------------------------------------------------------------------------------- /benchmarks/object.bench.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const wrap = require('module').wrap 3 | const bench = require('fastbench') 4 | let pino = require('pino') 5 | const fs = require('fs') 6 | const dest = process.platform === 'win32' ? fs.createWriteStream('\\\\.\\NUL') : fs.createWriteStream('/dev/null') 7 | const plog = pino(dest) 8 | 9 | process.env.DEBUG = 'dlog' 10 | const dlog = require('debug')('dlog') 11 | dlog.log = function (s) { dest.write(s) } 12 | 13 | delete require.cache[require.resolve('debug')] 14 | delete require.cache[require.resolve('debug/src/debug.js')] 15 | delete require.cache[require.resolve('debug/src/node')] 16 | 17 | delete require.cache[require.resolve('pino')] 18 | pino = require('pino') 19 | require('../')(pino({ level: 'debug' }, dest)) 20 | const pdlog = require('debug')('dlog') 21 | 22 | delete require.cache[require.resolve('debug')] 23 | delete require.cache[require.resolve('debug/src/debug.js')] 24 | delete require.cache[require.resolve('debug/src/node')] 25 | delete require.cache[require.resolve('../')] 26 | delete require.cache[require.resolve('../debug')] 27 | require('module').wrap = wrap 28 | 29 | require('../')(pino({ extreme: true, level: 'debug' }, dest)) 30 | const pedlog = require('debug')('dlog') 31 | 32 | const max = 10 33 | 34 | const run = bench([ 35 | function benchPinoObj (cb) { 36 | for (let i = 0; i < max; i++) { 37 | plog.info({ hello: 'world' }) 38 | } 39 | setImmediate(cb) 40 | }, 41 | function benchDebugObj (cb) { 42 | for (let i = 0; i < max; i++) { 43 | dlog({ hello: 'world' }) 44 | } 45 | setImmediate(cb) 46 | }, 47 | function benchPinoDebugObj (cb) { 48 | for (let i = 0; i < max; i++) { 49 | pdlog({ hello: 'world' }) 50 | } 51 | setImmediate(cb) 52 | }, 53 | function benchPinoExtremeDebugDeepObj (cb) { 54 | for (let i = 0; i < max; i++) { 55 | pedlog({ hello: 'world' }) 56 | } 57 | setImmediate(cb) 58 | } 59 | ], 10000) 60 | 61 | run(run) 62 | -------------------------------------------------------------------------------- /benchmarks/runbench.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs') 4 | const path = require('path') 5 | const spawn = require('child_process').spawn 6 | const pump = require('pump') 7 | const split = require('split2') 8 | const through = require('through2') 9 | const steed = require('steed') 10 | 11 | function usage () { 12 | return fs.createReadStream(path.join(__dirname, 'usage.txt')) 13 | } 14 | 15 | if (!process.argv[2]) { 16 | usage().pipe(process.stdout) 17 | process.exit() 18 | } 19 | 20 | let selectedBenchmark = process.argv[2].toLowerCase() 21 | const benchmarkDir = path.resolve(__dirname) 22 | const benchmarks = { 23 | basic: 'basic.bench.js', 24 | object: 'object.bench.js', 25 | deepobject: 'deep-object.bench.js' 26 | } 27 | 28 | function runBenchmark (name, done) { 29 | const benchmarkResults = {} 30 | benchmarkResults[name] = {} 31 | 32 | const processor = through(function (line, enc, cb) { 33 | const parts = ('' + line).split(': ') 34 | const parts2 = parts[0].split('*') 35 | const logger = parts2[0].replace('bench', '') 36 | 37 | if (!benchmarkResults[name][logger]) benchmarkResults[name][logger] = [] 38 | 39 | benchmarkResults[name][logger].push({ 40 | time: parts[1].replace('ms', ''), 41 | iterations: parts2[1].replace(':', '') 42 | }) 43 | 44 | cb() 45 | }) 46 | 47 | console.log('Running ' + name.toUpperCase() + ' benchmark\n') 48 | const benchmark = spawn( 49 | process.argv[0], 50 | [path.join(benchmarkDir, benchmarks[name])] 51 | ) 52 | 53 | benchmark.stdout.pipe(process.stdout) 54 | pump(benchmark.stdout, split(), processor) 55 | 56 | benchmark.on('exit', function () { 57 | console.log('') 58 | if (done && typeof done === 'function') done(null, benchmarkResults) 59 | }) 60 | } 61 | 62 | function sum (ar) { 63 | let result = 0 64 | for (let i = 0; i < ar.length; i += 1) { 65 | result += Number.parseFloat(ar[i].time) 66 | } 67 | return result 68 | } 69 | 70 | function displayResults (results) { 71 | console.log('==========') 72 | const benchNames = Object.keys(results) 73 | for (let i = 0; i < benchNames.length; i += 1) { 74 | console.log(benchNames[i] + ' averages') 75 | const benchmark = results[benchNames[i]] 76 | const loggers = Object.keys(benchmark) 77 | for (let j = 0; j < loggers.length; j += 1) { 78 | const logger = benchmark[loggers[j]] 79 | const average = Math.round(sum(logger) / logger.length) 80 | console.log(loggers[j] + ' average: ' + average) 81 | } 82 | } 83 | console.log('==========') 84 | } 85 | 86 | function toBench (done) { 87 | runBenchmark(this.name, done) 88 | } 89 | 90 | const benchQueue = [] 91 | if (selectedBenchmark !== 'all') { 92 | benchQueue.push(toBench.bind({ name: selectedBenchmark })) 93 | } else { 94 | const keys = Object.keys(benchmarks) 95 | for (let i = 0; i < keys.length; i += 1) { 96 | selectedBenchmark = keys[i] 97 | benchQueue.push(toBench.bind({ name: selectedBenchmark })) 98 | } 99 | } 100 | steed.series(benchQueue, function (err, results) { 101 | if (err) return console.error(err.message) 102 | results.forEach(displayResults) 103 | }) 104 | -------------------------------------------------------------------------------- /benchmarks/usage.txt: -------------------------------------------------------------------------------- 1 | Pino Benchmarks 2 | 3 | To run a benchmark, specify which to run: 4 | 5 | ・all ⁃ run all benchmarks (takes a while) 6 | ・basic ⁃ log a simple string 7 | ・object ⁃ logging a basic object 8 | ・deepobject ⁃ logging a large object 9 | 10 | Example: 11 | 12 | node runbench basic 13 | -------------------------------------------------------------------------------- /debug.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const util = require('util') 4 | 5 | module.exports = debug 6 | 7 | function debug (namespace) { 8 | if (!debug.logger) { 9 | throw Error('debug called before pino-debug initialized, ' + 10 | 'register pino-debug at the top of your entry point') 11 | } 12 | 13 | const logger = debug.logger.child({ ns: namespace }) 14 | const log = Array.from(debug.map.keys()).map(function (rx) { 15 | return rx.test(namespace) && logger[debug.map.get(rx)] 16 | }).filter(Boolean)[0] || logger.debug 17 | 18 | function disabled () {} 19 | disabled.enabled = false 20 | function enabled () { 21 | const message = util.format.apply(util, arguments) // this is how debug.js formats argeuments 22 | return log.apply(logger, [message]) 23 | } 24 | enabled.enabled = true 25 | 26 | const fn = debug.enabled(namespace) ? enabled : disabled 27 | fn.extend = function (subNamespace, delimiter) { 28 | return debug(namespace + (delimiter || ':') + subNamespace) 29 | } 30 | 31 | fn.namespace = namespace 32 | 33 | return fn 34 | } 35 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const path = require('path') 3 | const logger = require('morgan') 4 | const cookieParser = require('cookie-parser') 5 | const bodyParser = require('body-parser') 6 | 7 | const index = require('./routes/index') 8 | const users = require('./routes/users') 9 | 10 | const app = express() 11 | 12 | // view engine setup 13 | app.set('views', path.join(__dirname, 'views')) 14 | app.set('view engine', 'jade') 15 | 16 | app.use(logger('dev')) 17 | app.use(bodyParser.json()) 18 | app.use(bodyParser.urlencoded({ extended: false })) 19 | app.use(cookieParser()) 20 | app.use(express.static(path.join(__dirname, 'public'))) 21 | 22 | app.use('/', index) 23 | app.use('/users', users) 24 | 25 | // catch 404 and forward to error handler 26 | app.use(function (req, res, next) { 27 | const err = new Error('Not Found') 28 | err.status = 404 29 | next(err) 30 | }) 31 | 32 | // error handler 33 | app.use(function (err, req, res, next) { 34 | // set locals, only providing error in development 35 | res.locals.message = err.message 36 | res.locals.error = req.app.get('env') === 'development' ? err : {} 37 | 38 | // render the error page 39 | res.status(err.status || 500) 40 | res.render('error') 41 | }) 42 | 43 | module.exports = app 44 | -------------------------------------------------------------------------------- /example/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('example:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /example/bin/www-programmatic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * pino-debug hook 5 | */ 6 | 7 | 8 | var pinoDebug = require('../../'); // require('pino-debug') 9 | const logger = require('pino')({level: process.env.LEVEL || 'debug'}, process.stderr); 10 | pinoDebug(logger, { 11 | auto: true, // default 12 | map: { 13 | 'example:server': 'info', 14 | 'express:router': 'debug', 15 | '*': 'trace' // everything else - trace 16 | } 17 | }); 18 | 19 | /** 20 | * Module dependencies. 21 | */ 22 | 23 | var app = require('../app'); 24 | var debug = require('debug')('example:server'); 25 | var http = require('http'); 26 | 27 | /** 28 | * Get port from environment and store in Express. 29 | */ 30 | 31 | var port = normalizePort(process.env.PORT || '3000'); 32 | app.set('port', port); 33 | 34 | /** 35 | * Create HTTP server. 36 | */ 37 | 38 | var server = http.createServer(app); 39 | 40 | /** 41 | * Listen on provided port, on all network interfaces. 42 | */ 43 | 44 | server.listen(port); 45 | server.on('error', onError); 46 | server.on('listening', onListening); 47 | 48 | /** 49 | * Normalize a port into a number, string, or false. 50 | */ 51 | 52 | function normalizePort(val) { 53 | var port = parseInt(val, 10); 54 | 55 | if (isNaN(port)) { 56 | // named pipe 57 | return val; 58 | } 59 | 60 | if (port >= 0) { 61 | // port number 62 | return port; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | /** 69 | * Event listener for HTTP server "error" event. 70 | */ 71 | 72 | function onError(error) { 73 | if (error.syscall !== 'listen') { 74 | throw error; 75 | } 76 | 77 | var bind = typeof port === 'string' 78 | ? 'Pipe ' + port 79 | : 'Port ' + port; 80 | 81 | // handle specific listen errors with friendly messages 82 | switch (error.code) { 83 | case 'EACCES': 84 | console.error(bind + ' requires elevated privileges'); 85 | process.exit(1); 86 | break; 87 | case 'EADDRINUSE': 88 | console.error(bind + ' is already in use'); 89 | process.exit(1); 90 | break; 91 | default: 92 | throw error; 93 | } 94 | } 95 | 96 | /** 97 | * Event listener for HTTP server "listening" event. 98 | */ 99 | 100 | function onListening() { 101 | var addr = server.address(); 102 | var bind = typeof addr === 'string' 103 | ? 'pipe ' + addr 104 | : 'port ' + addr.port; 105 | debug('Listening on ' + bind); 106 | } 107 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "start-preload": "DEBUG=* node -r ../ ./bin/www", 8 | "start-programmatic": "node ./bin/www-programmatic", 9 | "start-programmatic-debug": "LEVEL=debug node ./bin/www-programmatic", 10 | "start-programmatic-trace": "LEVEL=trace node ./bin/www-programmatic" 11 | }, 12 | "dependencies": { 13 | "body-parser": "~1.15.2", 14 | "cookie-parser": "~1.4.3", 15 | "debug": "^3.1.0", 16 | "express": "~4.14.0", 17 | "jade": "~1.11.0", 18 | "morgan": "~1.7.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /example/routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const router = express.Router() 3 | /* GET home page. */ 4 | router.get('/', function (req, res, next) { 5 | res.render('index', { title: 'Express' }) 6 | }) 7 | 8 | module.exports = router 9 | -------------------------------------------------------------------------------- /example/routes/users.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const router = express.Router() 3 | 4 | /* GET users listing. */ 5 | router.get('/', function (req, res, next) { 6 | res.send('respond with a resource') 7 | }) 8 | 9 | module.exports = router 10 | -------------------------------------------------------------------------------- /example/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /example/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /example/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const pino = require('pino') 4 | require('module').wrap = override 5 | const debug = require('debug') 6 | 7 | module.exports = pinoDebug 8 | 9 | /* istanbul ignore next */ 10 | if (module.parent && module.parent.parent === null && module.parent.filename === null) { 11 | // preloaded with -r flag 12 | pinoDebug() 13 | } 14 | 15 | function pinoDebug (logger, opts) { 16 | if (pinoDebug.called) throw Error('pino-debug can only be called once') 17 | pinoDebug.called = true 18 | opts = opts || {} 19 | const auto = 'auto' in opts ? opts.auto : true 20 | const map = opts.map || {} 21 | const namespaces = getNamespaces() 22 | debug.map = Object.keys(map).sort(byPrecision).reduce(function (m, k) { 23 | if (auto) namespaces.push(k) 24 | m.set(RegExp('^' + k.replace(/[\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*?') + '$'), map[k]) 25 | return m 26 | }, new Map()) 27 | debug.logger = logger || pino({ level: 'debug' }) 28 | if (opts.skip) { 29 | opts.skip.map(function (ns) { return '-' + ns }).forEach(function (ns) { namespaces.push(ns) }) 30 | } 31 | debug.enable(namespaces.join(',')) 32 | } 33 | 34 | function getNamespaces () { 35 | const namespaces = process.env.DEBUG 36 | if (namespaces != null) { 37 | return (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/) 38 | } 39 | return [] 40 | } 41 | 42 | function byPrecision (a, b) { 43 | const aix = a.indexOf('*') 44 | const bix = b.indexOf('*') 45 | if (aix === -1 && bix === -1) return 0 46 | if (~aix && ~bix) { 47 | if (aix > bix) return -1 48 | if (aix < bix) return 1 49 | return a.length < b.length ? 1 : (a.length === b.length ? 0 : -1) 50 | } 51 | return ~bix ? -1 : 1 52 | } 53 | 54 | function override (script) { 55 | // Escape backslashes to prevent from interpreting backslashes on Windows platform 56 | // during expression interpolation in ES6 template literal. 57 | // Without this change, Windows path retrieved from require.resolve (eg. 58 | // F:\Projekty\Learn\pino-debug\debug.js) will be interpreted during interpolation 59 | // as F:ProjektyLearnpino-debugdebug.js and node.js will throw error 60 | // Cannot find module 'F:ProjektyLearnpino-debugdebug.js' 61 | const pathToPinoDebug = require.resolve('./debug').replace(/\\/g, '\\\\') 62 | 63 | const head = `(function(exports, require, module, __filename, __dirname) { 64 | require = (function (req) { 65 | var pinoDebugOs = require('os') 66 | var pinoDebugPath = require('path') 67 | var Object = ({}).constructor 68 | return Object.setPrototypeOf(function pinoDebugWrappedRequire(s) { 69 | var dirname = __dirname.split(pinoDebugPath.sep) 70 | var lastNodeModulesIndex = dirname.lastIndexOf('node_modules') 71 | var isDebug = lastNodeModulesIndex >= 0 && dirname[lastNodeModulesIndex + 1] === 'debug' 72 | var pathToPinoDebug = '${pathToPinoDebug}' 73 | 74 | if (isDebug) { 75 | var dbg = req(pathToPinoDebug) 76 | var real = req(s) 77 | if (s === './common') { 78 | var wrapped = function pinoDebugWrapSetup(env) { 79 | var orig = real(env) 80 | Object.assign(dbg, orig) 81 | Object.defineProperty(orig, 'save', {get: function () { 82 | Object.defineProperty(orig, 'save', {value: dbg.save}) 83 | return orig.save 84 | }, configurable: true}) 85 | return dbg 86 | } 87 | return wrapped 88 | } 89 | if (s === './debug') { 90 | Object.assign(dbg, real) 91 | Object.defineProperty(real, 'save', {get: function () { 92 | Object.defineProperty(real, 'save', {value: dbg.save}) 93 | return real.save 94 | }, configurable: true}) 95 | return dbg 96 | } 97 | } 98 | return req(s) 99 | }, req) 100 | }(require)) 101 | return (function(){ 102 | `.trim().replace(/\n/g, ';').replace(/\s+/g, ' ').replace(/;+/g, ';') 103 | const tail = '\n}).call(this);})' 104 | 105 | return head + script + tail 106 | } 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pino-debug", 3 | "version": "3.0.0", 4 | "description": "High performance debug logging", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm run deps && standard && npm run test:unit", 8 | "deps": "knip --production --dependencies", 9 | "standard": "standard", 10 | "standard:fix": "standard --fix", 11 | "test:unit": "cross-env NODE_ENV=test nyc tap", 12 | "test:watch": "cross-env NODE_ENV=test tap repl w", 13 | "test:with-debug": "npm i --no-save --no-audit --no-fund debug@$DEBUG_VERSION && npm run test:unit -- --after scripts/npmi", 14 | "test-2.3": "cross-env DEBUG_VERSION=2.3 npm run test:with-debug", 15 | "test-2.4": "cross-env DEBUG_VERSION=2.4 npm run test:with-debug", 16 | "test-2.5": "cross-env DEBUG_VERSION=2.5 npm run test:with-debug", 17 | "test-2.6": "cross-env DEBUG_VERSION=2.6 npm run test:with-debug", 18 | "test-3.1": "cross-env DEBUG_VERSION=3.1 npm run test:with-debug", 19 | "test-4.1": "cross-env DEBUG_VERSION=4.1 npm run test:with-debug", 20 | "test-all": "npm run test-2.3 && npm run test-2.4 && npm run test-2.5 && npm run test-2.6 && npm run test-3.1 && npm run test-4.1", 21 | "ci": "npm test", 22 | "bench": "node benchmarks/runbench all", 23 | "bench-basic": "node benchmarks/runbench basic", 24 | "bench-object": "node benchmarks/runbench object", 25 | "bench-deepobject": "node benchmarks/runbench deepobject" 26 | }, 27 | "repository": "pinojs/pino-debug", 28 | "keywords": [ 29 | "pino", 30 | "debug", 31 | "fast", 32 | "performance", 33 | "debugging", 34 | "logging", 35 | "logger" 36 | ], 37 | "license": "MIT", 38 | "dependencies": { 39 | "pino": "^9.0.0" 40 | }, 41 | "peerDependencies": { 42 | "debug": ">=2" 43 | }, 44 | "devDependencies": { 45 | "cross-env": "^7.0.3", 46 | "fastbench": "^1.0.1", 47 | "knip": "^5.1.2", 48 | "nyc": "^15.1.0", 49 | "pump": "^3.0.0", 50 | "split2": "^4.2.0", 51 | "standard": "^17.1.0", 52 | "steed": "^1.1.3", 53 | "tap": "^18.7.1", 54 | "through2": "^4.0.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /scripts/npmi.js: -------------------------------------------------------------------------------- 1 | // Cleanup after testing specific debug version 2 | const { spawnSync } = require('child_process') 3 | spawnSync('npm', ['i'], { stdio: 'ignore' }) 4 | -------------------------------------------------------------------------------- /test/fixtures/line-numbers.js: -------------------------------------------------------------------------------- 1 | module.exports = function lineNum () { 2 | const orig = Error.prepareStackTrace 3 | Error.prepareStackTrace = function (_, stack) { return stack } 4 | const err = new Error() 5 | const stack = err.stack 6 | Error.prepareStackTrace = orig 7 | return stack[0].getLineNumber() 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/object-override.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // stylus literally does this -- https://git.io/vyPlO 3 | const Object = function Object () {} 4 | 5 | module.exports = Object 6 | -------------------------------------------------------------------------------- /test/fixtures/strict-mode.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* eslint-disable-next-line */ 4 | eval('var test = 123') 5 | 6 | // This will evaluate to `true` if strict mode is enabled 7 | module.exports = typeof test === 'undefined' 8 | -------------------------------------------------------------------------------- /test/fixtures/trailing-comment.js: -------------------------------------------------------------------------------- 1 | /* eslint eol-last: off */ 2 | 3 | module.exports = 1 4 | // trailing comment -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const { exec, execSync } = require('child_process') 5 | const tap = require('tap') 6 | const through = require('through2') 7 | const test = tap.test 8 | 9 | const debugModules = [ 10 | // <= 2.4 11 | [ 12 | 'debug/node.js', 13 | 'debug/debug.js' 14 | ], 15 | // <= 4.0.1 16 | [ 17 | 'debug/node.js', 18 | 'debug/src/node.js', 19 | 'debug/src/debug.js' 20 | ], 21 | [ 22 | 'debug/src/node.js', 23 | 'debug/src/common.js' 24 | ] 25 | ] 26 | 27 | const commonModules = [ 28 | 'debug', 29 | '../debug', 30 | '../', 31 | './' 32 | ] 33 | 34 | tap.afterEach(() => { 35 | let err = null 36 | for (const modules of debugModules) { 37 | try { 38 | commonModules.concat(modules) 39 | .map(m => require.resolve(m)) 40 | .forEach(k => delete require.cache[k]) 41 | err = null 42 | break 43 | } catch (e) { 44 | err = e 45 | } 46 | } 47 | if (err) { 48 | throw err 49 | } 50 | process.env.DEBUG = '' 51 | }) 52 | 53 | test('throws if called more than once', (t) => { 54 | const pinoDebug = require('../') 55 | t.throws(() => { 56 | pinoDebug() 57 | pinoDebug() 58 | }) 59 | t.end() 60 | }) 61 | 62 | test('throws if debug is called after requiring but before calling pinoDebug', (t) => { 63 | require('../') 64 | const debug = require('debug') 65 | t.throws(() => debug('ns')) 66 | t.end() 67 | }) 68 | 69 | test('captures any calls to `debug` and passes them through pino logger', (t) => { 70 | const pinoDebug = require('../') 71 | const stream = through((line, _, cb) => { 72 | const obj = JSON.parse(line) 73 | t.equal(obj.msg, 'test') 74 | t.equal(obj.ns, 'ns') 75 | t.end() 76 | }) 77 | pinoDebug(require('pino')({ level: 'debug' }, stream)) 78 | const debug = require('debug') 79 | debug.enable('ns') 80 | debug('ns')('test') 81 | }) 82 | 83 | test('defaults to calling pinoInstance.debug', (t) => { 84 | const pinoDebug = require('../') 85 | const stream = through((line, _, cb) => { 86 | const obj = JSON.parse(line) 87 | t.equal(obj.msg, 'test') 88 | t.equal(obj.ns, 'ns') 89 | t.equal(obj.level, 20) 90 | t.end() 91 | }) 92 | pinoDebug(require('pino')({ level: 'debug' }, stream)) 93 | const debug = require('debug') 94 | debug.enable('ns') 95 | debug('ns')('test') 96 | }) 97 | 98 | test('when passed no args, creates a standard pino logger with log level set to debug and logs to it\'s debug method', (t) => { 99 | const debug = path.join(__dirname, '..') 100 | const program = ` 101 | var pinoDebug = require('${debug}') 102 | var write = process.stdout.write 103 | pinoDebug() 104 | var debug = require('debug') 105 | debug.enable('ns') 106 | debug('ns')('test') 107 | ` 108 | 109 | exec(`${process.argv[0]} -e "${program}"`, (err, stdout, stderr) => { 110 | t.error(err) 111 | console.log(stdout.toString()) 112 | console.log(stderr.toString()) 113 | const line = stdout.toString() 114 | const obj = JSON.parse(line) 115 | t.equal(obj.msg, 'test') 116 | t.equal(obj.ns, 'ns') 117 | t.equal(obj.level, 20) 118 | t.end() 119 | }) 120 | }) 121 | 122 | test('passes debug args to pino log method according to opts.map', (t) => { 123 | const pinoDebug = require('../') 124 | const stream = through((line, _, cb) => { 125 | const obj = JSON.parse(line) 126 | t.equal(obj.msg, 'test') 127 | t.equal(obj.ns, 'ns') 128 | t.equal(obj.level, 30) 129 | t.end() 130 | }) 131 | pinoDebug(require('pino')(stream), { map: { ns: 'info' } }) 132 | const debug = require('debug') 133 | debug('ns')('test') 134 | }) 135 | 136 | test('passes debug args to pino log method according to opts.map when auto is off but namespaces have been enabled', (t) => { 137 | const pinoDebug = require('../') 138 | const ns = (line) => { 139 | const obj = JSON.parse(line) 140 | t.equal(obj.msg, 'test') 141 | t.equal(obj.ns, 'ns') 142 | t.equal(obj.level, 30) 143 | } 144 | const ns2 = (line) => { 145 | const obj = JSON.parse(line) 146 | t.equal(obj.msg, 'test2') 147 | t.equal(obj.ns, 'ns2') 148 | t.equal(obj.level, 40) 149 | } 150 | const stream = through((line, _, cb) => { 151 | if (!ns.called) { 152 | ns(line) 153 | ns.called = true 154 | cb() 155 | return 156 | } 157 | ns2(line) 158 | t.end() 159 | }) 160 | 161 | pinoDebug(require('pino')(stream), { auto: false, map: { ns: 'info', ns2: 'warn' } }) 162 | let debug = require('debug') 163 | debug.enable('ns') 164 | debug('ns')('test') 165 | debug = require('debug') 166 | debug.enable('ns2') 167 | debug('ns2')('test2') 168 | }) 169 | 170 | test('does not pass debug args to pino log method according to opts.map when auto is off and namespaces have not been enabled', (t) => { 171 | const pinoDebug = require('../') 172 | 173 | const stream = through((line, _, cb) => { 174 | const obj = JSON.parse(line) 175 | t.equal(obj.msg, 'test2') 176 | t.equal(obj.ns, 'ns2') 177 | t.equal(obj.level, 40) 178 | t.end() 179 | cb() 180 | }) 181 | 182 | pinoDebug(require('pino')(stream), { auto: false, map: { ns: 'info', ns2: 'warn' } }) 183 | const debug = require('debug') 184 | debug.enable('ns2') 185 | debug('ns')('test') 186 | debug('ns2')('test2') 187 | }) 188 | 189 | test('when preloaded with -r, automatically logs all debug calls with log level debug to a default pino logger', (t) => { 190 | const program = ` 191 | var debug = require('debug') 192 | debug('ns')('test') 193 | ` 194 | const debug = path.join(__dirname, '..') 195 | const line = execSync(`${process.argv[0]} -r ${debug} -e "${program}"`, { env: { DEBUG: '*' } }).toString() 196 | const obj = JSON.parse(line) 197 | t.equal(obj.msg, 'test') 198 | t.equal(obj.ns, 'ns') 199 | t.equal(obj.level, 20) 200 | t.end() 201 | }) 202 | 203 | test('opts.skip filters out any matching namespaces', (t) => { 204 | const pinoDebug = require('../') 205 | 206 | const stream = through((line, _, cb) => { 207 | const obj = JSON.parse(line) 208 | t.equal(obj.msg, 'test') 209 | t.equal(obj.ns, 'ns') 210 | t.equal(obj.level, 30) 211 | t.end() 212 | cb() 213 | }) 214 | 215 | pinoDebug(require('pino')(stream), { 216 | map: { 'ns*': 'info' }, 217 | skip: ['ns2'] 218 | }) 219 | const debug = require('debug') 220 | debug('ns2')('test2') 221 | debug('ns')('test') 222 | }) 223 | 224 | test('when there is a match conflict, log level is set to most precise match', (t) => { 225 | const pinoDebug = require('../') 226 | 227 | const queue = [(line) => { 228 | const obj = JSON.parse(line) 229 | t.equal(obj.msg, 'test') 230 | t.equal(obj.ns, 'ns') 231 | t.equal(obj.level, 30) 232 | }, (line) => { 233 | const obj = JSON.parse(line) 234 | t.equal(obj.msg, 'test2') 235 | t.equal(obj.ns, 'ns2') 236 | t.equal(obj.level, 40) 237 | }, (line) => { 238 | const obj = JSON.parse(line) 239 | t.equal(obj.msg, 'test3') 240 | t.equal(obj.ns, 'meow') 241 | t.equal(obj.level, 50) 242 | }, (line) => { 243 | const obj = JSON.parse(line) 244 | t.equal(obj.msg, 'test4') 245 | t.equal(obj.ns, 'izikilla') 246 | t.equal(obj.level, 60) 247 | }, (line) => { 248 | const obj = JSON.parse(line) 249 | t.equal(obj.msg, 'test5') 250 | t.equal(obj.ns, 'testtracetest') 251 | t.equal(obj.level, 10) 252 | }, (line) => { 253 | const obj = JSON.parse(line) 254 | t.equal(obj.msg, 'test6') 255 | t.equal(obj.ns, 'debugtra') 256 | t.equal(obj.level, 20) 257 | }, (line) => { 258 | const obj = JSON.parse(line) 259 | t.equal(obj.msg, 'test7') 260 | t.equal(obj.ns, 'ns3') 261 | t.equal(obj.level, 20) 262 | }, (line) => { 263 | const obj = JSON.parse(line) 264 | t.equal(obj.msg, 'test8') 265 | t.equal(obj.ns, 'testbla') 266 | t.equal(obj.level, 30) 267 | }] 268 | 269 | const stream = through((line, _, cb) => { 270 | queue.shift()(line) 271 | cb() 272 | if (!queue.length) t.end() 273 | }) 274 | 275 | pinoDebug(require('pino')({ level: 'trace' }, stream), { 276 | map: { 277 | '*tra': 'debug', 278 | '*bla': 'info', 279 | '*': 'error', 280 | '*killa': 'fatal', 281 | ns2: 'warn', 282 | ns3: 'debug', 283 | 'ns*': 'info', 284 | '*trace*': 'trace' 285 | } 286 | }) 287 | const debug = require('debug') 288 | debug('ns')('test') 289 | debug('ns2')('test2') 290 | debug('meow')('test3') 291 | debug('izikilla')('test4') 292 | debug('testtracetest')('test5') 293 | debug('debugtra')('test6') 294 | debug('ns3')('test7') 295 | debug('testbla')('test8') 296 | }) 297 | 298 | test('uses native `Object` regardless of wrapped file contents', (t) => { 299 | t.doesNotThrow(() => require('./fixtures/object-override')) 300 | t.end() 301 | }) 302 | 303 | test('keeps line numbers consistent', (t) => { 304 | require('../') 305 | const lineNums = require('./fixtures/line-numbers') 306 | const line = lineNums() 307 | t.equal(line, 4) 308 | 309 | t.end() 310 | }) 311 | 312 | test('results in valid syntax when source has trailing comment', (t) => { 313 | t.doesNotThrow(() => require('./fixtures/trailing-comment')) 314 | t.end() 315 | }) 316 | 317 | test('preserves DEBUG env independently from debug module', (t) => { 318 | process.env.DEBUG = 'ns1' 319 | const pinoDebug = require('../') 320 | const stream = through((line, _, cb) => { 321 | const obj = JSON.parse(line) 322 | t.equal(obj.msg, 'test') 323 | t.equal(obj.ns, 'ns1') 324 | t.end() 325 | }) 326 | pinoDebug(require('pino')({ level: 'debug' }, stream)) 327 | const debug = require('debug') 328 | debug('ns1')('test') 329 | }) 330 | 331 | test('supports extend method', (t) => { 332 | process.env.DEBUG = '*' 333 | const pinoDebug = require('../') 334 | const ns = ['ns1', 'ns1:ns2', 'ns1;ns2'] 335 | let count = 0 336 | const stream = through((line, _, cb) => { 337 | const obj = JSON.parse(line) 338 | t.equal(obj.msg, 'test') 339 | t.equal(obj.ns, ns[count++]) 340 | cb() 341 | }, () => t.end()) 342 | pinoDebug(require('pino')({ level: 'debug' }, stream)) 343 | const debug = require('debug') 344 | debug('ns1')('test') 345 | debug('ns1').extend('ns2')('test') 346 | debug('ns1').extend('ns2', ';')('test') 347 | stream.end() 348 | }) 349 | 350 | test('does not invalidate strict mode', (t) => { 351 | t.equal(require('./fixtures/strict-mode'), true) 352 | t.end() 353 | }) 354 | 355 | test('Process all arguments debug.js style', (t) => { 356 | const testOptions = { option1: 'value1' } 357 | process.env.DEBUG = 'ns1' 358 | const pinoDebug = require('../') 359 | const stream = through((line, _, cb) => { 360 | const obj = JSON.parse(line) 361 | const expectedMsg = "test { option1: 'value1' }" 362 | t.equal(obj.msg, expectedMsg) 363 | t.equal(obj.ns, 'ns1') 364 | t.end() 365 | }) 366 | pinoDebug(require('pino')({ level: 'debug' }, stream)) 367 | const debug = require('debug') 368 | 369 | debug('ns1')('test', testOptions) 370 | }) 371 | --------------------------------------------------------------------------------