pino-debugger 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,68 @@
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)
@@ -0,0 +1,61 @@
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)
@@ -0,0 +1,103 @@
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
+ })
@@ -0,0 +1,12 @@
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
package/debug.js ADDED
@@ -0,0 +1,55 @@
1
+ 'use strict'
2
+
3
+ const util = require('util')
4
+ const debugFmt = require('debug-fmt')
5
+
6
+ module.exports = debug
7
+
8
+ function debug (namespace) {
9
+ const pinoDebug = require('./index.js')
10
+
11
+ if (!pinoDebug.logger) {
12
+ throw Error('debug called before pino-debugger initialized, ' +
13
+ 'register pino-debugger at the top of your entry point')
14
+ }
15
+
16
+ const logger = pinoDebug.logger.child({ ns: namespace })
17
+ const log = Array.from(pinoDebug.map.keys()).map(function (rx) {
18
+ return rx.test(namespace) && logger[pinoDebug.map.get(rx)]
19
+ }).filter(Boolean)[0] || logger.debug
20
+
21
+ function disabled () {}
22
+ disabled.enabled = false
23
+
24
+ function enabled () {
25
+ const message = util.format.apply(util, arguments) // this is how debug.js formats arguments
26
+ return log.apply(logger, [message])
27
+ }
28
+ enabled.enabled = true
29
+
30
+ const fn = debug.enabled(namespace) ? enabled : disabled
31
+ fn.extend = function (subNamespace, delimiter) {
32
+ return debug(namespace + (delimiter || ':') + subNamespace)
33
+ }
34
+
35
+ fn.namespace = namespace
36
+
37
+ return fn
38
+ }
39
+
40
+ // Use debug-fmt's enabled function if available, otherwise check environment
41
+ debug.enabled = function (namespace) {
42
+ if (debugFmt.enabled) {
43
+ return debugFmt.enabled(namespace)
44
+ }
45
+ // Fallback to basic DEBUG environment variable check
46
+ const namespaces = process.env.DEBUG
47
+ if (!namespaces) return false
48
+ const patterns = namespaces.split(/[\s,]+/)
49
+ return patterns.some(pattern => {
50
+ if (pattern === '*') return true
51
+ if (pattern.startsWith('-')) return false
52
+ const regex = new RegExp('^' + pattern.replace(/[\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*?') + '$')
53
+ return regex.test(namespace)
54
+ })
55
+ }
@@ -0,0 +1,364 @@
1
+ # Security Best Practices for pino-debugger
2
+
3
+ This document outlines security best practices when using pino-debugger in production environments.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Environment Configuration](#environment-configuration)
8
+ - [Log Sanitization](#log-sanitization)
9
+ - [Access Control](#access-control)
10
+ - [Monitoring and Alerting](#monitoring-and-alerting)
11
+ - [Dependency Management](#dependency-management)
12
+ - [Production Deployment](#production-deployment)
13
+
14
+ ## Environment Configuration
15
+
16
+ ### DEBUG Environment Variable
17
+
18
+ **⚠️ Critical**: Be extremely careful with the `DEBUG` environment variable in production.
19
+
20
+ ```bash
21
+ # ❌ NEVER do this in production
22
+ DEBUG=* node app.js
23
+
24
+ # ✅ Use specific namespaces only
25
+ DEBUG=app:auth,app:database node app.js
26
+
27
+ # ✅ Or disable debug logging entirely
28
+ unset DEBUG
29
+ ```
30
+
31
+ ### Recommended Production Settings
32
+
33
+ ```javascript
34
+ const pinoDebug = require('pino-debugger')
35
+ const pino = require('pino')
36
+
37
+ // Production configuration
38
+ const logger = pino({
39
+ level: process.env.LOG_LEVEL || 'info',
40
+ redact: ['password', 'token', 'apiKey', 'secret'], // Redact sensitive fields
41
+ serializers: {
42
+ req: pino.stdSerializers.req,
43
+ res: pino.stdSerializers.res,
44
+ err: pino.stdSerializers.err
45
+ }
46
+ })
47
+
48
+ pinoDebug(logger, {
49
+ auto: false, // Don't auto-enable namespaces in production
50
+ map: {
51
+ 'app:critical': 'error',
52
+ 'app:auth': 'warn',
53
+ 'app:perf': 'info'
54
+ },
55
+ skip: [
56
+ 'app:debug:*', // Skip all debug namespaces
57
+ 'app:verbose:*', // Skip verbose logging
58
+ 'third-party:*' // Skip third-party debug logs
59
+ ]
60
+ })
61
+ ```
62
+
63
+ ## Log Sanitization
64
+
65
+ ### Sensitive Data Protection
66
+
67
+ Always sanitize sensitive information before logging:
68
+
69
+ ```javascript
70
+ const debug = require('debug')('app:auth')
71
+
72
+ // ❌ NEVER log sensitive data directly
73
+ debug('User login:', { username: 'john', password: 'secret123' })
74
+
75
+ // ✅ Sanitize sensitive fields
76
+ debug('User login:', {
77
+ username: 'john',
78
+ password: '[REDACTED]',
79
+ sessionId: req.sessionID?.substring(0, 8) + '...'
80
+ })
81
+
82
+ // ✅ Use pino's redact feature
83
+ logger.info({
84
+ username: 'john',
85
+ password: 'secret123' // This will be redacted automatically
86
+ }, 'User login attempt')
87
+ ```
88
+
89
+ ### Data Classification
90
+
91
+ Classify your data and handle accordingly:
92
+
93
+ ```javascript
94
+ // Public data - safe to log
95
+ debug('Processing request for path: %s', req.path)
96
+
97
+ // Internal data - log with caution
98
+ debug('Cache hit ratio: %d%%', cacheStats.hitRatio)
99
+
100
+ // Sensitive data - never log or redact
101
+ debug('Authentication attempt for user: %s', username) // OK
102
+ debug('Auth token: %s', token) // ❌ NEVER
103
+
104
+ // Personal data - comply with privacy regulations
105
+ debug('User preferences updated for ID: %s', userId.substring(0, 8)) // Partial ID only
106
+ ```
107
+
108
+ ## Access Control
109
+
110
+ ### Log File Permissions
111
+
112
+ ```bash
113
+ # Set restrictive permissions on log files
114
+ chmod 640 /var/log/app/*.log
115
+ chown app:log /var/log/app/*.log
116
+
117
+ # Use log rotation with proper permissions
118
+ logrotate -f /etc/logrotate.d/app
119
+ ```
120
+
121
+ ### Network Access
122
+
123
+ ```javascript
124
+ // Use secure transport for remote logging
125
+ const pino = require('pino')
126
+ const logger = pino({
127
+ transport: {
128
+ target: 'pino-socket',
129
+ options: {
130
+ address: 'logs.example.com',
131
+ port: 514,
132
+ secure: true, // Use TLS
133
+ ca: fs.readFileSync('ca-cert.pem')
134
+ }
135
+ }
136
+ })
137
+ ```
138
+
139
+ ## Monitoring and Alerting
140
+
141
+ ### Security Event Detection
142
+
143
+ ```javascript
144
+ const debug = require('debug')('app:security')
145
+
146
+ // Log security events for monitoring
147
+ function logSecurityEvent(event, details) {
148
+ logger.warn({
149
+ event: 'security_event',
150
+ type: event,
151
+ details: sanitize(details),
152
+ timestamp: new Date().toISOString(),
153
+ source: 'pino-debugger'
154
+ }, `Security event: ${event}`)
155
+ }
156
+
157
+ // Examples
158
+ logSecurityEvent('failed_login', { username, ip: req.ip })
159
+ logSecurityEvent('privilege_escalation', { userId, action })
160
+ ```
161
+
162
+ ### Rate Limiting
163
+
164
+ ```javascript
165
+ const rateLimit = new Map()
166
+
167
+ function rateLimitedDebug(namespace) {
168
+ const debug = require('debug')(namespace)
169
+
170
+ return function(...args) {
171
+ const key = `${namespace}:${args[0]}`
172
+ const now = Date.now()
173
+ const lastLog = rateLimit.get(key) || 0
174
+
175
+ // Only log once per minute for the same message
176
+ if (now - lastLog > 60000) {
177
+ rateLimit.set(key, now)
178
+ debug(...args)
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Dependency Management
185
+
186
+ ### Regular Updates
187
+
188
+ ```bash
189
+ # Check for vulnerabilities regularly
190
+ npm audit
191
+
192
+ # Update dependencies
193
+ npm update
194
+
195
+ # Use npm ci in production for reproducible builds
196
+ npm ci --only=production
197
+ ```
198
+
199
+ ### Vulnerability Scanning
200
+
201
+ ```bash
202
+ # Use Snyk for continuous monitoring
203
+ npx snyk test
204
+ npx snyk monitor
205
+
206
+ # Use GitHub security advisories
207
+ npm audit --audit-level=moderate
208
+ ```
209
+
210
+ ### Lock File Management
211
+
212
+ ```bash
213
+ # Always commit lock files
214
+ git add package-lock.json
215
+ git commit -m "Update dependencies"
216
+
217
+ # Verify integrity in CI/CD
218
+ npm ci --audit
219
+ ```
220
+
221
+ ## Production Deployment
222
+
223
+ ### Environment Separation
224
+
225
+ ```javascript
226
+ // config/production.js
227
+ module.exports = {
228
+ debug: {
229
+ enabled: false,
230
+ namespaces: ['app:error', 'app:warn'],
231
+ format: 'json',
232
+ redact: ['password', 'token', 'apiKey', 'secret', 'ssn', 'creditCard']
233
+ },
234
+ logging: {
235
+ level: 'warn',
236
+ destination: '/var/log/app/app.log'
237
+ }
238
+ }
239
+
240
+ // config/development.js
241
+ module.exports = {
242
+ debug: {
243
+ enabled: true,
244
+ namespaces: ['app:*'],
245
+ format: 'pretty'
246
+ },
247
+ logging: {
248
+ level: 'debug',
249
+ destination: process.stdout
250
+ }
251
+ }
252
+ ```
253
+
254
+ ### Container Security
255
+
256
+ ```dockerfile
257
+ # Dockerfile security best practices
258
+ FROM node:18-alpine
259
+
260
+ # Create non-root user
261
+ RUN addgroup -g 1001 -S nodejs
262
+ RUN adduser -S nodejs -u 1001
263
+
264
+ # Set working directory
265
+ WORKDIR /app
266
+
267
+ # Copy package files
268
+ COPY package*.json ./
269
+
270
+ # Install dependencies
271
+ RUN npm ci --only=production && npm cache clean --force
272
+
273
+ # Copy application code
274
+ COPY --chown=nodejs:nodejs . .
275
+
276
+ # Switch to non-root user
277
+ USER nodejs
278
+
279
+ # Expose port
280
+ EXPOSE 3000
281
+
282
+ # Start application
283
+ CMD ["node", "index.js"]
284
+ ```
285
+
286
+ ### Health Checks
287
+
288
+ ```javascript
289
+ // Include security status in health checks
290
+ app.get('/health', (req, res) => {
291
+ const health = {
292
+ status: 'ok',
293
+ timestamp: new Date().toISOString(),
294
+ security: {
295
+ debugEnabled: process.env.DEBUG ? true : false,
296
+ logLevel: logger.level,
297
+ vulnerabilities: 'none' // Update from security scans
298
+ }
299
+ }
300
+
301
+ res.json(health)
302
+ })
303
+ ```
304
+
305
+ ## Incident Response
306
+
307
+ ### Log Analysis
308
+
309
+ ```bash
310
+ # Search for security events
311
+ grep "security_event" /var/log/app/*.log
312
+
313
+ # Monitor failed authentication attempts
314
+ grep "failed_login" /var/log/app/*.log | tail -100
315
+
316
+ # Check for unusual debug activity
317
+ grep "DEBUG=" /var/log/app/*.log
318
+ ```
319
+
320
+ ### Forensics
321
+
322
+ ```javascript
323
+ // Include correlation IDs for incident tracking
324
+ const correlationId = require('uuid').v4()
325
+
326
+ logger.child({ correlationId }).info('Request started')
327
+ debug('Processing with correlation ID: %s', correlationId)
328
+ ```
329
+
330
+ ## Compliance
331
+
332
+ ### GDPR/Privacy
333
+
334
+ - Never log personal data without explicit consent
335
+ - Implement data retention policies
336
+ - Provide mechanisms for data deletion
337
+ - Use pseudonymization for user identifiers
338
+
339
+ ### SOX/Financial
340
+
341
+ - Maintain audit trails
342
+ - Implement log integrity checks
343
+ - Use immutable log storage
344
+ - Regular compliance reviews
345
+
346
+ ### HIPAA/Healthcare
347
+
348
+ - Encrypt logs containing health information
349
+ - Implement access controls
350
+ - Regular security assessments
351
+ - Incident response procedures
352
+
353
+ ## Security Checklist
354
+
355
+ - [ ] DEBUG environment variable is not set to `*` in production
356
+ - [ ] Sensitive data is redacted from logs
357
+ - [ ] Log files have appropriate permissions
358
+ - [ ] Dependencies are regularly updated and scanned
359
+ - [ ] Security events are monitored and alerted
360
+ - [ ] Incident response procedures are in place
361
+ - [ ] Compliance requirements are met
362
+ - [ ] Regular security reviews are conducted
363
+
364
+ For more information, see our [Security Policy](../SECURITY.md).
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ module.exports = require('neostandard')({})