Skip to content

Commit

Permalink
Node: configurable util.inspect() options (#327)
Browse files Browse the repository at this point in the history
* `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
  • Loading branch information
TooTallNate authored and thebigredgeek committed Dec 12, 2016
1 parent 00f3046 commit e58d54b
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 67 deletions.
30 changes: 23 additions & 7 deletions Readme.md → README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,36 @@ 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

The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.

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


Expand Down Expand Up @@ -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
Expand Down
7 changes: 2 additions & 5 deletions browser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/**
* This is the web browser implementation of `debug()`.
*
Expand Down Expand Up @@ -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' : '')
Expand Down Expand Up @@ -101,7 +99,6 @@ function formatArgs() {
});

args.splice(lastC, 0, c);
return args;
}

/**
Expand Down Expand Up @@ -172,7 +169,7 @@ exports.enable(load());
* @api private
*/

function localstorage(){
function localstorage() {
try {
return window.localStorage;
} catch (e) {}
Expand Down
40 changes: 19 additions & 21 deletions debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 = {};
Expand Down Expand Up @@ -66,17 +66,13 @@ function selectColor(namespace) {
* @api public
*/

function debug(namespace) {
function createDebug(namespace) {

// define the `disabled` version
function disabled() {
}
disabled.enabled = false;

// define the `enabled` version
function enabled() {
function debug() {
// disabled?
if (!debug.enabled) return;

var self = enabled;
var self = debug;

// set `diff` timestamp
var curr = +new Date();
Expand All @@ -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];
Expand Down Expand Up @@ -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();

This comment has been minimized.

Copy link
@dickeylth

dickeylth Dec 15, 2016

I'm using webpack-dev-server and here may throw Uncaught TypeError: exports.useColors is not a function

debug.color = selectColor(namespae);

This comment has been minimized.

Copy link
@knewter

knewter Dec 14, 2016

Heads up, this breaks things because this is the wrong name for the variable :(

This comment has been minimized.

Copy link
@amklose

amklose Dec 14, 2016

This should say debug.color = selectColor(namespace);


fn.namespace = namespace;
// env-specific initialization logic for debug instances
if ('function' === typeof exports.init) {
exports.init(debug);
}

return fn;
return debug;
}

/**
Expand Down
88 changes: 54 additions & 34 deletions node.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/**
* Module dependencies.
*/
Expand All @@ -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;
Expand All @@ -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.:
Expand All @@ -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);
};

/**
Expand All @@ -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;
Expand All @@ -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');
}

/**
Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit e58d54b

Please sign in to comment.