1'use strict'; 2 3const { 4 ObjectCreate, 5 ObjectDefineProperty, 6 RegExp, 7 RegExpPrototypeExec, 8 SafeArrayIterator, 9 StringPrototypeToLowerCase, 10 StringPrototypeToUpperCase, 11} = primordials; 12 13const { inspect, format, formatWithOptions } = require('internal/util/inspect'); 14 15// `debugImpls` and `testEnabled` are deliberately not initialized so any call 16// to `debuglog()` before `initializeDebugEnv()` is called will throw. 17let debugImpls; 18let testEnabled; 19 20 21// `debugEnv` is initial value of process.env.NODE_DEBUG 22function initializeDebugEnv(debugEnv) { 23 debugImpls = ObjectCreate(null); 24 if (debugEnv) { 25 // This is run before any user code, it's OK not to use primordials. 26 debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&') 27 .replaceAll('*', '.*') 28 .replaceAll(',', '$|^'); 29 const debugEnvRegex = new RegExp(`^${debugEnv}$`, 'i'); 30 testEnabled = (str) => RegExpPrototypeExec(debugEnvRegex, str) !== null; 31 } else { 32 testEnabled = () => false; 33 } 34} 35 36// Emits warning when user sets 37// NODE_DEBUG=http or NODE_DEBUG=http2. 38function emitWarningIfNeeded(set) { 39 if ('HTTP' === set || 'HTTP2' === set) { 40 process.emitWarning('Setting the NODE_DEBUG environment variable ' + 41 'to \'' + StringPrototypeToLowerCase(set) + '\' can expose sensitive ' + 42 'data (such as passwords, tokens and authentication headers) ' + 43 'in the resulting log.'); 44 } 45} 46 47const noop = () => {}; 48 49let utilColors; 50function lazyUtilColors() { 51 utilColors ??= require('internal/util/colors'); 52 return utilColors; 53} 54 55function debuglogImpl(enabled, set) { 56 if (debugImpls[set] === undefined) { 57 if (enabled) { 58 const pid = process.pid; 59 emitWarningIfNeeded(set); 60 debugImpls[set] = function debug(...args) { 61 const colors = lazyUtilColors().shouldColorize(process.stderr); 62 const msg = formatWithOptions({ colors }, ...args); 63 const coloredPID = inspect(pid, { colors }); 64 process.stderr.write(format('%s %s: %s\n', set, coloredPID, msg)); 65 }; 66 } else { 67 debugImpls[set] = noop; 68 } 69 } 70 return debugImpls[set]; 71} 72 73// debuglogImpl depends on process.pid and process.env.NODE_DEBUG, 74// so it needs to be called lazily in top scopes of internal modules 75// that may be loaded before these run time states are allowed to 76// be accessed. 77function debuglog(set, cb) { 78 function init() { 79 set = StringPrototypeToUpperCase(set); 80 enabled = testEnabled(set); 81 } 82 let debug = (...args) => { 83 init(); 84 // Only invokes debuglogImpl() when the debug function is 85 // called for the first time. 86 debug = debuglogImpl(enabled, set); 87 if (typeof cb === 'function') 88 cb(debug); 89 switch (args.length) { 90 case 1: return debug(args[0]); 91 case 2: return debug(args[0], args[1]); 92 default: return debug(...new SafeArrayIterator(args)); 93 } 94 }; 95 let enabled; 96 let test = () => { 97 init(); 98 test = () => enabled; 99 return enabled; 100 }; 101 const logger = (...args) => { 102 switch (args.length) { 103 case 1: return debug(args[0]); 104 case 2: return debug(args[0], args[1]); 105 default: return debug(...new SafeArrayIterator(args)); 106 } 107 }; 108 ObjectDefineProperty(logger, 'enabled', { 109 __proto__: null, 110 get() { 111 return test(); 112 }, 113 configurable: true, 114 enumerable: true, 115 }); 116 return logger; 117} 118 119module.exports = { 120 debuglog, 121 initializeDebugEnv, 122}; 123