Node: configurable util.inspect() options (#327)

* `formatArgs()` gets passed the args Array directly

Rather than working on `arguments`. The Node.js version
was for some reason turning the arguments into an Array
again so it was happening twice! This should make things
faster overall.

* whitespace

* rename `Readme.md` to `README.md`

* refactor the `debug()` constructor a bit

Now, debug instances are hot-enabelable. That is, you can
toggle the `debug.enabled` boolean on instances to enable
or disable an instance. There is still no global version of
this functionality.

Now all instances get a `useColors` and `colors` property,
even disabled ones, in case they get enabled later on. Boot-up
time impact should be negligible.

* node: allow configurable `util.inspect()` options

Via env variables by default. So to get more object depth,
you pass the `DEBUG_DEPTH=10` env var.

For the `showHidden` option, you set `DEBUG_SHOW_HIDDEN=on`.

See the Node.js docs for the complete list of `util.inspect()` options:
https://nodejs.org/api/util.html#util_util_inspect_object_options

* README: document inspect env variables
This commit is contained in:
Nathan Rajlich 2016-12-12 15:13:35 -08:00 committed by Andrew E. Rhyne
parent 00f3046c30
commit e58d54b46f
4 changed files with 98 additions and 67 deletions

View File

@ -79,7 +79,7 @@ Then, run the program to be debugged as usual.
## Conventions
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
## Wildcards
@ -87,6 +87,28 @@ Then, run the program to be debugged as usual.
You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".
## Environment Variables
When running through Node.js, you can set a few environment variables that will
change the behavior of the debug logging:
| Name | Purpose |
|-----------|-------------------------------------------------|
| `DEBUG` | Enables/disabled specific debugging namespaces. |
| `DEBUG_COLORS`| Whether or not to use colors in the debug output. |
| `DEBUG_FD`| File descriptor to output debug logs to. Defaults to stderr. |
| `DEBUG_DEPTH` | Object inspection depth. |
| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. |
__Note:__ The environment variables beginning with `DEBUG_` end up being
converted into an Options object that gets used with `%o`/`%O` formatters.
See the Node.js documentation for
[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
for the complete list.
__Note:__ Certain IDEs (such as WebStorm) don't support colors on stderr. In these cases you must set `DEBUG_COLORS` to `1` and additionally change `DEBUG_FD` to `1`.
## Formatters
@ -191,12 +213,6 @@ Example:
$ DEBUG_FD=3 node your-app.js 3> whatever.log
```
### Terminal colors
By default colors will only be used in a TTY. However this can be overridden by setting the environment variable `DEBUG_COLORS` to `1`.
Note: Certain IDEs (such as WebStorm) don't support colors on stderr. In these cases you must set `DEBUG_COLORS` to `1` and additionally change `DEBUG_FD` to `1`.
## Authors
- TJ Holowaychuk

View File

@ -1,4 +1,3 @@
/**
* This is the web browser implementation of `debug()`.
*
@ -69,8 +68,7 @@ exports.formatters.j = function(v) {
* @api public
*/
function formatArgs() {
var args = arguments;
function formatArgs(args) {
var useColors = this.useColors;
args[0] = (useColors ? '%c' : '')
@ -101,7 +99,6 @@ function formatArgs() {
});
args.splice(lastC, 0, c);
return args;
}
/**
@ -172,7 +169,7 @@ exports.enable(load());
* @api private
*/
function localstorage(){
function localstorage() {
try {
return window.localStorage;
} catch (e) {}

View File

@ -6,7 +6,7 @@
* Expose `debug()` as the module.
*/
exports = module.exports = debug.debug = debug;
exports = module.exports = createDebug.debug = createDebug.default = createDebug;
exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
@ -23,7 +23,7 @@ exports.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lowercased letter, i.e. "n".
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
*/
exports.formatters = {};
@ -66,17 +66,13 @@ function selectColor(namespace) {
* @api public
*/
function debug(namespace) {
function createDebug(namespace) {
// define the `disabled` version
function disabled() {
}
disabled.enabled = false;
function debug() {
// disabled?
if (!debug.enabled) return;
// define the `enabled` version
function enabled() {
var self = enabled;
var self = debug;
// set `diff` timestamp
var curr = +new Date();
@ -86,10 +82,7 @@ function debug(namespace) {
self.curr = curr;
prevTime = curr;
// add the `color` if not set
if (null == self.useColors) self.useColors = exports.useColors();
if (null == self.color && self.useColors) self.color = selectColor(namespace);
// turn the `arguments` into a proper Array
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
@ -120,19 +113,24 @@ function debug(namespace) {
return match;
});
// apply env-specific formatting
args = exports.formatArgs.apply(self, args);
// apply env-specific formatting (colors, etc.)
exports.formatArgs.call(self, args);
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
var fn = exports.enabled(namespace) ? enabled : disabled;
debug.namespace = namespace;
debug.enabled = exports.enabled(namespace);
debug.useColors = exports.useColors();
debug.color = selectColor(namespae);
fn.namespace = namespace;
// env-specific initialization logic for debug instances
if ('function' === typeof exports.init) {
exports.init(debug);
}
return fn;
return debug;
}
/**

88
node.js
View File

@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@ -13,6 +12,7 @@ var util = require('util');
*/
exports = module.exports = require('./debug');
exports.init = init;
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
@ -25,6 +25,32 @@ exports.useColors = useColors;
exports.colors = [6, 2, 3, 4, 5, 1];
/**
* Build up the default `inspectOpts` object from the environment variables.
*
* $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
*/
exports.inspectOpts = Object.keys(process.env).filter(function (key) {
return /^debug_/i.test(key);
}).reduce(function (obj, key) {
// camel-case
var prop = key
.substring(6)
.toLowerCase()
.replace(/_([a-z])/, function (_, k) { return k.toUpperCase() });
// coerce string value into JS value
var val = process.env[key];
if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
else if (val === 'null') val = null;
else val = Number(val);
obj[prop] = val;
return obj;
}, {});
/**
* The file descriptor to write the `debug()` calls to.
* Set the `DEBUG_FD` env variable to override with another value. i.e.:
@ -42,39 +68,28 @@ var stream = 1 === fd ? process.stdout :
*/
function useColors() {
var debugColors = (process.env.DEBUG_COLORS || '').trim().toLowerCase();
if (0 === debugColors.length) {
return tty.isatty(fd);
} else {
return '0' !== debugColors
&& 'no' !== debugColors
&& 'false' !== debugColors
&& 'disabled' !== debugColors;
}
return 'colors' in exports.inspectOpts
? Boolean(exports.inspectOpts.colors)
: tty.isatty(fd);
}
/**
* Map %o to `util.inspect()`, since Node doesn't do that out of the box.
* Map %o to `util.inspect()`, all on a single line.
*/
var inspect = (4 === util.inspect.length ?
// node <= 0.8.x
function (v, colors) {
return util.inspect(v, void 0, void 0, colors);
} :
// node > 0.8.x
function (v, colors) {
return util.inspect(v, { colors: colors });
}
);
exports.formatters.o = function(v) {
return inspect(v, this.useColors)
this.inspectOpts.colors = this.useColors;
return util.inspect(v, this.inspectOpts)
.replace(/\s*\n\s*/g, ' ');
};
/**
* Map %o to `util.inspect()`, allowing multiple lines if needed.
*/
exports.formatters.O = function(v) {
return inspect(v, this.useColors);
this.inspectOpts.colors = this.useColors;
return util.inspect(v, this.inspectOpts);
};
/**
@ -83,14 +98,9 @@ exports.formatters.O = function(v) {
* @api public
*/
function formatArgs() {
var len = arguments.length;
var args = new Array(len);
var useColors = this.useColors;
function formatArgs(args) {
var name = this.namespace;
for (var i = 0; i < len; i++) {
args[i] = arguments[i];
}
var useColors = this.useColors;
if (useColors) {
var c = this.color;
@ -102,15 +112,14 @@ function formatArgs() {
args[0] = new Date().toUTCString()
+ ' ' + name + ' ' + args[0];
}
return args;
}
/**
* Invokes `console.error()` with the specified arguments.
* Invokes `util.format()` with the specified arguments and writes to `stream`.
*/
function log() {
return stream.write(util.format.apply(this, arguments) + '\n');
return stream.write(util.format.apply(util, arguments) + '\n');
}
/**
@ -209,6 +218,17 @@ function createWritableStdioStream (fd) {
return stream;
}
/**
* Init logic for `debug` instances.
*
* Create a new `inspectOpts` object in case `useColors` is set
* differently for a particular `debug` instance.
*/
function init (debug) {
debug.inspectOpts = util._extend({}, exports.inspectOpts);
}
/**
* Enable namespaces listed in `process.env.DEBUG` initially.
*/