Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/api/console.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ object. This is useful for inspecting large complicated objects. Defaults to
- `colors` - if `true`, then the output will be styled with ANSI color codes.
Defaults to `false`. Colors are customizable, see below.

### console.group([data][, ...])

Starts a new logging group with an optional title. All console output that occurs
after calling this method and calling `console.groupEnd` has the same
indent level.

### console.groupCollapsed([data][, ...])

Same as `console.group`.

### console.groupEnd()

Closes the most recent logging group that was created with `console.group` or
`console.groupCollapsed`.

### console.time(label)

Used to calculate the duration of a specific operation. To start a timer, call
Expand Down
30 changes: 27 additions & 3 deletions lib/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function Console(stdout, stderr) {
Object.defineProperty(this, '_stderr', prop);
prop.value = new Map();
Object.defineProperty(this, '_times', prop);
prop.value = 0;
Object.defineProperty(this, '_group', prop);

// bind the prototype functions to this Console instance
var keys = Object.keys(Console.prototype);
Expand All @@ -33,15 +35,17 @@ function Console(stdout, stderr) {
}

Console.prototype.log = function() {
this._stdout.write(util.format.apply(this, arguments) + '\n');
this._stdout.write(util.format.apply(this, arguments).replace(/^/gm,
Array(this._group * 2 + 1).join(' ')) + '\n');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about ' '.repeat(this._group * 2) ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just wanted to keep console as lightweight and performant as possible.

String.prototype.repeat is bit slower than Array.join method I chose.

See http://jsperf.com/faster-string-repeat/15

I do agree that ' '.repeat() is more readable in code.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want performance, define this._group as string.
in group function do this._group += ' '
in this function do:

var data = util.format.apply(this, arguments);
if (this._group.length) data = data.replace(/^/gm, this._group);
this._stdout.write(data + '\n');

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a check that grouping is used before allocating all these arrays and strings

I also think it's better to just write the indentation, instead of concatenating it and then writing it anyway

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This jsperf is using a shim for String.prototype.repeat. Native is faster
Anyway both show that Array#join is the slowest of all

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for reviewing and providing input. I tried to be minimal and not introduce lot of new code and variables to core lib.

I'll update the PR soon based on your comments.

@3y3 For tracking multiple levels of grouping I'd still keep numeric _group but generate a fixed prefix string which would be conditionally concatenated as @petkaantonov suggested. This adds variables and code, but I think it pleases everyone?

};


Console.prototype.info = Console.prototype.log;


Console.prototype.warn = function() {
this._stderr.write(util.format.apply(this, arguments) + '\n');
this._stderr.write(util.format.apply(this, arguments).replace(/^/gm,
Array(this._group * 2 + 1).join(' ')) + '\n');
};


Expand All @@ -51,7 +55,27 @@ Console.prototype.error = Console.prototype.warn;
Console.prototype.dir = function(object, options) {
this._stdout.write(util.inspect(object, util._extend({
customInspect: false
}, options)) + '\n');
}, options)).replace(/^/gm, Array(this._group * 2 + 1).join(' ')) + '\n');
};


Console.prototype.group = function() {
if (arguments.length) {
this.log.apply(this, arguments);
}
this._group++;
};


Console.prototype.groupCollapsed = function() {
this.group.apply(this, arguments);
};


Console.prototype.groupEnd = function() {
if ( this._group > 0 ) {
this._group--;
}
};


Expand Down
67 changes: 67 additions & 0 deletions test/parallel/test-console-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
var common = require('../common');
var assert = require('assert');

assert.ok(process.stdout.writable);
assert.ok(process.stderr.writable);
// Support legacy API
assert.equal('number', typeof process.stdout.fd);
assert.equal('number', typeof process.stderr.fd);

assert.doesNotThrow(function () {
console.group('label');
console.groupEnd();
});

assert.doesNotThrow(function () {
console.groupCollapsed('label');
console.groupEnd();
});

// test multiple calls to console.groupEnd()
assert.doesNotThrow(function () {
console.groupEnd();
console.groupEnd();
console.groupEnd();
});

var stdout_write = global.process.stdout.write;
var strings = [];
global.process.stdout.write = function(string) {
strings.push(string);
};
console._stderr = process.stdout;

// test console.group(), console.groupCollapsed() and console.groupEnd()
console.log('foo');
console.group('bar');
console.log('foo bar');
console.groupEnd();
console.groupCollapsed('group 1');
console.log('log');
console.warn('warn');
console.error('error');
console.dir({ foo: true });
console.group('group 2');
console.log('foo bar hop');
console.log('line 1\nline 2\nline 3');
console.groupEnd();
console.log('end 2');
console.groupEnd();
console.log('end 1');

global.process.stdout.write = stdout_write;

assert.equal('foo\n', strings.shift());
assert.equal('bar\n', strings.shift());
assert.equal(' foo bar\n', strings.shift());
assert.equal("group 1\n", strings.shift());
assert.equal(' log\n', strings.shift());
assert.equal(' warn\n', strings.shift());
assert.equal(' error\n', strings.shift());
assert.equal(' { foo: true }\n', strings.shift());
assert.equal(' group 2\n', strings.shift());
assert.equal(' foo bar hop\n', strings.shift());
assert.equal(' line 1\n line 2\n line 3\n', strings.shift());
assert.equal(' end 2\n', strings.shift());
assert.equal('end 1\n', strings.shift());
assert.equal(strings.length, 0);