Skip to content

Commit ae21f06

Browse files
bmeckMylesBorins
authored andcommitted
util: add debug and debuglog.enabled
PR-URL: #33424 Reviewed-By: James M Snell <[email protected]>
1 parent e4d3dbd commit ae21f06

File tree

4 files changed

+74
-14
lines changed

4 files changed

+74
-14
lines changed

doc/api/util.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,42 @@ let debuglog = util.debuglog('internals', (debug) => {
136136
});
137137
```
138138

139+
### `debuglog().enabled`
140+
<!-- YAML
141+
added: REPLACEME
142+
-->
143+
144+
* {boolean}
145+
146+
The `util.debuglog().enabled` getter is used to create a test that can be used
147+
in conditionals based on the existence of the `NODE_DEBUG` environment variable.
148+
If the `section` name appears within the value of that environment variable,
149+
then the returned value will be `true`. If not, then the returned value will be
150+
`false`.
151+
152+
```js
153+
const util = require('util');
154+
const enabled = util.debuglog('foo').enabled;
155+
if (enabled) {
156+
console.log('hello from foo [%d]', 123);
157+
}
158+
```
159+
160+
If this program is run with `NODE_DEBUG=foo` in the environment, then it will
161+
output something like:
162+
163+
```console
164+
hello from foo [123]
165+
```
166+
167+
## `util.debug(section)`
168+
<!-- YAML
169+
added: REPLACEME
170+
-->
171+
172+
Alias for `util.debuglog`. Usage allows for readability of that doesn't imply
173+
logging when only using `util.debuglog().enabled`.
174+
139175
## `util.deprecate(fn, msg[, code])`
140176
<!-- YAML
141177
added: v0.8.0

lib/internal/util/debuglog.js

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
'use strict';
22

33
const {
4+
FunctionPrototypeBind,
5+
ObjectCreate,
6+
ObjectDefineProperty,
47
RegExp,
8+
RegExpPrototypeTest,
9+
StringPrototypeToUpperCase
510
} = primordials;
611

712
const { inspect, format, formatWithOptions } = require('internal/util/inspect');
813

914
// `debugs` is deliberately initialized to undefined so any call to
1015
// debuglog() before initializeDebugEnv() is called will throw.
11-
let debugs;
16+
let debugImpls;
1217

1318
let debugEnvRegex = /^$/;
19+
let testEnabled;
1420

1521
// `debugEnv` is initial value of process.env.NODE_DEBUG
1622
function initializeDebugEnv(debugEnv) {
17-
debugs = {};
23+
debugImpls = ObjectCreate(null);
1824
if (debugEnv) {
1925
debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&')
2026
.replace(/\*/g, '.*')
2127
.replace(/,/g, '$|^')
2228
.toUpperCase();
2329
debugEnvRegex = new RegExp(`^${debugEnv}$`, 'i');
2430
}
31+
testEnabled = FunctionPrototypeBind(RegExpPrototypeTest, null, debugEnvRegex);
2532
}
2633

2734
// Emits warning when user sets
@@ -37,41 +44,57 @@ function emitWarningIfNeeded(set) {
3744

3845
function noop() {}
3946

40-
function debuglogImpl(set) {
41-
set = set.toUpperCase();
42-
if (debugs[set] === undefined) {
43-
if (debugEnvRegex.test(set)) {
47+
function debuglogImpl(enabled, set) {
48+
if (debugImpls[set] === undefined) {
49+
if (enabled) {
4450
const pid = process.pid;
4551
emitWarningIfNeeded(set);
46-
debugs[set] = function debug(...args) {
52+
debugImpls[set] = function debug(...args) {
4753
const colors = process.stderr.hasColors && process.stderr.hasColors();
4854
const msg = formatWithOptions({ colors }, ...args);
4955
const coloredPID = inspect(pid, { colors });
5056
process.stderr.write(format('%s %s: %s\n', set, coloredPID, msg));
5157
};
5258
} else {
53-
debugs[set] = noop;
59+
debugImpls[set] = noop;
5460
}
5561
}
56-
return debugs[set];
62+
return debugImpls[set];
5763
}
5864

5965
// debuglogImpl depends on process.pid and process.env.NODE_DEBUG,
6066
// so it needs to be called lazily in top scopes of internal modules
6167
// that may be loaded before these run time states are allowed to
6268
// be accessed.
6369
function debuglog(set, cb) {
70+
function init() {
71+
set = StringPrototypeToUpperCase(set);
72+
enabled = testEnabled(set);
73+
}
6474
let debug = (...args) => {
75+
init();
6576
// Only invokes debuglogImpl() when the debug function is
6677
// called for the first time.
67-
debug = debuglogImpl(set);
78+
debug = debuglogImpl(enabled, set);
6879
if (typeof cb === 'function')
6980
cb(debug);
7081
debug(...args);
7182
};
72-
return (...args) => {
73-
debug(...args);
83+
let enabled;
84+
let test = () => {
85+
init();
86+
test = () => enabled;
87+
return enabled;
7488
};
89+
const logger = (...args) => debug(...args);
90+
ObjectDefineProperty(logger, 'enabled', {
91+
get() {
92+
return test();
93+
},
94+
configurable: true,
95+
enumerable: true
96+
});
97+
return logger;
7598
}
7699

77100
module.exports = {

lib/util.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ module.exports = {
239239
_exceptionWithHostPort: exceptionWithHostPort,
240240
_extend,
241241
callbackify,
242+
debug: debuglog,
242243
debuglog,
243244
deprecate,
244245
format,

test/sequential/test-util-debug.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function parent() {
5757

5858
function test(environ, shouldWrite, section, forceColors = false) {
5959
let expectErr = '';
60-
const expectOut = 'ok\n';
60+
const expectOut = shouldWrite ? 'enabled\n' : 'disabled\n';
6161

6262
const spawn = require('child_process').spawn;
6363
const child = spawn(process.execPath, [__filename, 'child', section], {
@@ -123,5 +123,5 @@ function child(section) {
123123
}));
124124
debug('this', { is: 'a' }, /debugging/);
125125
debug('num=%d str=%s obj=%j', 1, 'a', { foo: 'bar' });
126-
console.log('ok');
126+
console.log(debug.enabled ? 'enabled' : 'disabled');
127127
}

0 commit comments

Comments
 (0)