diff --git a/lib/util.js b/lib/util.js index 401d55bbe82926..b09dd768ff6e65 100644 --- a/lib/util.js +++ b/lib/util.js @@ -62,17 +62,26 @@ exports.deprecate = function(fn, msg) { } var warned = false; + const warnedLines = new Set(); + function deprecated() { + var location = (new Error()).stack.match(/.*?\n.*\n.*?\((.*?:\d+):/)[1]; + if (!warned) { if (process.throwDeprecation) { throw new Error(msg); } else if (process.traceDeprecation) { - console.trace(msg); + if (!warnedLines.has(location)) { + warnedLines.add(location); + console.trace(msg); + } + warned = true; } else { console.error(msg); } - warned = true; + warned = !warned; } + return fn.apply(this, arguments); } @@ -766,38 +775,38 @@ exports.p = exports.deprecate(function() { for (var i = 0, len = arguments.length; i < len; ++i) { console.error(exports.inspect(arguments[i])); } -}, 'util.p: Use console.error() instead'); +}, '[node] util.p is deprecated. Use console.error instead'); exports.exec = exports.deprecate(function() { return require('child_process').exec.apply(this, arguments); -}, 'util.exec is now called `child_process.exec`.'); +}, '[node] util.exec is deprecated. Use child_process.exec instead'); exports.print = exports.deprecate(function() { for (var i = 0, len = arguments.length; i < len; ++i) { process.stdout.write(String(arguments[i])); } -}, 'util.print: Use console.log instead'); +}, '[node] util.print is deprecated. Use console.log instead'); exports.puts = exports.deprecate(function() { for (var i = 0, len = arguments.length; i < len; ++i) { process.stdout.write(arguments[i] + '\n'); } -}, 'util.puts: Use console.log instead'); +}, '[node] util.puts is deprecated. Use console.log instead'); exports.debug = exports.deprecate(function(x) { process.stderr.write('DEBUG: ' + x + '\n'); -}, 'util.debug: Use console.error instead'); +}, '[node] util.debug is deprecated. Use console.error instead'); exports.error = exports.deprecate(function(x) { for (var i = 0, len = arguments.length; i < len; ++i) { process.stderr.write(arguments[i] + '\n'); } -}, 'util.error: Use console.error instead'); +}, '[node] util.error is deprecated. Use console.error instead'); exports.pump = exports.deprecate(function(readStream, writeStream, callback) { @@ -835,7 +844,7 @@ exports.pump = exports.deprecate(function(readStream, writeStream, callback) { readStream.destroy(); call(err); }); -}, 'util.pump(): Use readableStream.pipe() instead'); +}, '[node] util.pump is deprecated. Use readableStream.pipe instead'); exports._errnoException = function(err, syscall, original) { diff --git a/test/fixtures/deprecated-multiple-times-same-line.js b/test/fixtures/deprecated-multiple-times-same-line.js new file mode 100644 index 00000000000000..709bea9f4b87d4 --- /dev/null +++ b/test/fixtures/deprecated-multiple-times-same-line.js @@ -0,0 +1 @@ +require('util').p('This is deprecated'); require('util').p('This is deprecated'); diff --git a/test/fixtures/deprecated-multiple-times.js b/test/fixtures/deprecated-multiple-times.js new file mode 100644 index 00000000000000..639040d4bde9b3 --- /dev/null +++ b/test/fixtures/deprecated-multiple-times.js @@ -0,0 +1,3 @@ +require('util').p('This is deprecated'); +require('util').p('This is deprecated'); +require('util').p('This is deprecated'); diff --git a/test/sequential/test-deprecation-flags.js b/test/sequential/test-deprecation-flags.js index e8565a33635744..c8fb47abda5357 100644 --- a/test/sequential/test-deprecation-flags.js +++ b/test/sequential/test-deprecation-flags.js @@ -8,13 +8,20 @@ var node = process.execPath; var normal = [depmod]; var noDep = ['--no-deprecation', depmod]; var traceDep = ['--trace-deprecation', depmod]; +var traceDepMultiple = ['--trace-deprecation', + require.resolve('../fixtures/deprecated-multiple-times.js')]; +var traceDepMultipleSameLine = ['--trace-deprecation', + require.resolve('../fixtures/deprecated-multiple-times-same-line.js')]; +var traceMessage = + 'Trace: [node] util.p is deprecated. Use console.error instead'; execFile(node, normal, function(er, stdout, stderr) { console.error('normal: show deprecation warning'); assert.equal(er, null); assert.equal(stdout, ''); assert.equal(stderr, - 'util.p: Use console.error() instead\n\'This is deprecated\'\n'); + '[node] util.p is deprecated. ' + + 'Use console.error instead\n\'This is deprecated\'\n'); console.log('normal ok'); }); @@ -32,7 +39,37 @@ execFile(node, traceDep, function(er, stdout, stderr) { assert.equal(stdout, ''); var stack = stderr.trim().split('\n'); // just check the top and bottom. - assert.equal(stack[0], 'Trace: util.p: Use console.error() instead'); + assert.equal(stack[0], traceMessage); assert.equal(stack.pop(), '\'This is deprecated\''); console.log('trace ok'); }); + +execFile(node, traceDepMultiple, function(er, stdout, stderr) { + console.error('--trace-deprecation: deprecation message printed 3 times'); + assert.equal(er, null); + assert.equal(stdout, ''); + + var count = stderr.trim().split('\n').filter(function(currentLine) { + return currentLine === traceMessage; + }).length; + + // because we invoked the same function three times + assert.equal(count, 3); + + console.log('trace ok'); +}); + +execFile(node, traceDepMultipleSameLine, function(er, stdout, stderr) { + console.error('--trace-deprecation: deprecation message printed only once'); + assert.equal(er, null); + assert.equal(stdout, ''); + + var count = stderr.trim().split('\n').filter(function(currentLine) { + return currentLine === traceMessage; + }).length; + + // because we invoked the same function two times, but in the same line + assert.equal(count, 1); + + console.log('trace ok'); +});