• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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