diff --git a/Readme.md b/Readme.md index bae742d4..3b58f5bf 100644 --- a/Readme.md +++ b/Readme.md @@ -147,6 +147,34 @@ error('now goes to stdout via console.info'); log('still goes to stdout, but via console.info now'); ``` +### Inspecting objects + +Objects can be included in the debug output using the `%o` formatting directive, which displays the object in the inspector on browsers and uses `util.inspect` on Node. Objects which require special formatting can be output using `.inspect` on the debug instance. It accepts the same options as `util.inspect` and can be overridden for each namespace: + +Example _inspect.js_: + +```js +var debug = require('debug'); + +var error = debug('app:error'); +// inspect hidden properties of a single object +error('stdin', error.inspect(new Error('Oh snap'), {showHidden: true})); + +var shallow = debug('app:shallow'); +// default depth 0 for all formatted objects in this namespace +var debugInspect = shallow.inspect; +shallow.inspect = function(object, options) { + return debugInspect.call(this, object, Object.assign({depth: 0}, options)); +}; +shallow('console properties: %o', console); +``` + +Some advantages of using `debug.inspect` over `util.inspect` are: + +* It avoids unnecessary formatting work when debugging is disabled for the namespace. +* It shares the same colorization default as the `debug`-formatted output. +* It becomes a no-op on browsers to avoid interfering with the inspector. + ### Save debug output to a file You can save all debug statements to a file by piping them. diff --git a/browser.js b/browser.js index 7c764522..7af7351c 100644 --- a/browser.js +++ b/browser.js @@ -6,6 +6,7 @@ */ exports = module.exports = require('./debug'); +exports.inspect = inspect; exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -47,6 +48,14 @@ function useColors() { (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31); } +/** + * Compatibility inspect function which returns its argument to allow + * unconditional debug.inspect(foo) usage without interfering with inspector. + */ +function inspect(o) { + return o; +} + /** * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. */ diff --git a/debug.js b/debug.js index a21c0930..e0e818bb 100644 --- a/debug.js +++ b/debug.js @@ -120,6 +120,7 @@ function debug(namespace) { var fn = exports.enabled(namespace) ? enabled : disabled; + fn.inspect = exports.inspect; fn.namespace = namespace; return fn; diff --git a/example/inspect.js b/example/inspect.js new file mode 100644 index 00000000..fd1192f4 --- /dev/null +++ b/example/inspect.js @@ -0,0 +1,13 @@ +var debug = require('../'); + +var error = debug('app:error'); +// inspect hidden properties of a single object +error('stdin', error.inspect(new Error('Oh snap'), {showHidden: true})); + +var shallow = debug('app:shallow'); +// default depth 0 for all formatted objects in this namespace +var debugInspect = shallow.inspect; +shallow.inspect = function(object, options) { + return debugInspect.call(this, object, Object.assign({depth: 0}, options)); +}; +shallow('console: %o', console); diff --git a/node.js b/node.js index 1d392a81..79499d60 100644 --- a/node.js +++ b/node.js @@ -13,6 +13,7 @@ var util = require('util'); */ exports = module.exports = require('./debug'); +exports.inspect = inspect; exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -53,25 +54,54 @@ function useColors() { } } -/** - * Map %o to `util.inspect()`, since Node doesn't do that out of the box. - */ - -var inspect = (4 === util.inspect.length ? +// Compatibility wrapper for util.inspect +var utilInspect = (4 === util.inspect.length ? // node <= 0.8.x - function (v, colors) { - return util.inspect(v, void 0, void 0, colors); + function (v, options) { + return util.inspect(v, options.showHidden, options.depth, options.colors); } : // node > 0.8.x - function (v, colors) { - return util.inspect(v, { colors: colors }); - } + util.inspect ); -exports.formatters.o = function(v) { - return inspect(v, this.useColors) - .replace(/\s*\n\s*/g, ' '); -}; +/** + * Inspects an object when debugging is enabled, producing single-line output + * and default colorization matching debug. + * + * @param {Object} object Object to inspect. + * @param {Object} options Options passed to util.inspect. + * @return {String} Inspection of argument object if enabled, otherwise an + * empty string. + * @api public + */ + +function inspect(object, options) { + if (this && this.enabled === false) { + return ''; + } + + var optionsWithColors = options; + if (!optionsWithColors || typeof optionsWithColors.colors === 'undefined') { + // Note: Careful of inspect being called before debug + var useColors = + this && typeof this.useColors !== 'undefined' ? this.useColors : + exports.useColors; + optionsWithColors = { + colors: typeof useColors === 'function' ? useColors() : useColors + }; + for (var prop in options) { + optionsWithColors[prop] = options[prop]; + } + } + + return utilInspect(object, optionsWithColors).replace(/\s*\n\s*/g, ' '); +} + +/** + * Map %o to `this.inspect()`, since Node doesn't provide %o out of the box. + */ + +exports.formatters.o = function(v) { return this.inspect(v); }; /** * Adds ANSI color escape codes if enabled.