From 27c71a92c13007c07f9132cf24974f36d691d4ff Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 7 Jan 2022 11:58:54 -0700 Subject: [PATCH] feat!: Highlight timestamp as util.inspect hightlights Dates (#23) chore: Fix flakey tests in CI --- README.md | 22 ++++++++++---- index.js | 24 ++++++++++----- package.json | 4 +-- test/index.js | 82 +++++++++++++++++++++++++++++++++++---------------- 4 files changed, 90 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 0695f1c..28d12cb 100644 --- a/README.md +++ b/README.md @@ -27,27 +27,39 @@ log.error('oh no!'); ### `log(msg...)` Logs the message as if you called `console.log` but prefixes the output with the -current time in HH:MM:ss format. +current time in HH:mm:ss format. ### `log.error(msg...)` Logs the message as if you called `console.error` but prefixes the output with the -current time in HH:MM:ss format. +current time in HH:mm:ss format. ### `log.warn(msg...)` Logs the message as if you called `console.warn` but prefixes the output with the -current time in HH:MM:ss format. +current time in HH:mm:ss format. ### `log.info(msg...)` Logs the message as if you called `console.info` but prefixes the output with the -current time in HH:MM:ss format. +current time in HH:mm:ss format. ### `log.dir(msg...)` Logs the message as if you called `console.dir` but prefixes the output with the -current time in HH:MM:ss format. +current time in HH:mm:ss format. + +## Styling + +If the terminal that you are logging to supports colors, the timestamp will be formatted as though it were a `Date` being formatted by `util.inspect()`. This means that it will be formatted as magenta by default but can be adjusted following node's [Customizing util.inspect colors](https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_customizing_util_inspect_colors) documentation. + +For example, this will cause the logged timestamps (and other dates) to display in red: + +```js +var util = require('util'); + +util.inspect.styles.date = 'red'; +``` ## License diff --git a/index.js b/index.js index c659e13..8b3dfec 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ 'use strict'; +var util = require('util'); var Console = require('console').Console; -var gray = require('ansi-gray'); -var timestamp = require('time-stamp'); var supportsColor = require('color-support'); var console = new Console({ @@ -15,24 +14,33 @@ function hasFlag(flag) { return process.argv.indexOf('--' + flag) !== -1; } -function addColor(str) { +function hasColors() { if (hasFlag('no-color')) { - return str; + return false; } if (hasFlag('color')) { - return gray(str); + return true; } if (supportsColor()) { - return gray(str); + return true; } - return str; + return false; +} + +function Timestamp() { + this.now = new Date(); +} + +Timestamp.prototype[util.inspect.custom] = function (depth, opts) { + var timestamp = this.now.toLocaleTimeString('en', { hour12: false }); + return '[' + opts.stylize(timestamp, 'date') + ']'; } function getTimestamp() { - return '[' + addColor(timestamp('HH:mm:ss')) + ']'; + return util.inspect(new Timestamp(), { colors: hasColors() }); } function log() { diff --git a/package.json b/package.json index f2e719c..b9d9504 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,7 @@ "test": "nyc mocha --async-only" }, "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^2.2.0" + "color-support": "^1.1.3" }, "devDependencies": { "eslint": "^7.32.0", diff --git a/test/index.js b/test/index.js index 5fa8669..47cc287 100644 --- a/test/index.js +++ b/test/index.js @@ -13,18 +13,60 @@ var nodeVersion = require('parse-node-version')(process.version); var isLessThanNode12 = nodeVersion.major < 12; var util = require('util'); +var inspect = util.inspect; var expect = require('expect'); var sinon = require('sinon'); -var gray = require('ansi-gray'); -var timestamp = require('time-stamp'); + +/* eslint-disable node/no-unsupported-features/es-syntax */ +// Reference: https://github.com/nodejs/node/blob/4e2ceba/lib/internal/util/inspect.js#L267-L274 +function stylizeWithColor(str, styleType) { + const style = inspect.styles[styleType]; + if (style !== undefined) { + const color = inspect.colors[style]; + + return `\u001b[${color[0]}m${str}\u001b[${color[1]}m`; + } + return str; +} +/* eslint-enable node/no-unsupported-features/es-syntax */ + +function withColor(str) { + return stylizeWithColor(str, 'date'); +} var log = require('../'); var stdoutSpy = sinon.spy(process.stdout, 'write'); var stderrSpy = sinon.spy(process.stderr, 'write'); +function expectCloseTo(arg, needsColor) { + var now = new Date(); + var time; + var maxAttempts = 5; + for (var attempts = 1; attempts < maxAttempts; attempts++) { + try { + time = now.toLocaleTimeString('en', { hour12: false }); + if (needsColor) { + expect(arg).toEqual('[' + withColor(time) + '] '); + } else { + expect(arg).toEqual('[' + time + '] '); + } + // Return on a success + return; + } catch (err) { + if (attempts === maxAttempts) { + throw err; + } else { + now.setSeconds(now.getSeconds() - 1); + } + } + } +} + describe('log()', function () { + this.timeout(5000); + var term = process.env.TERM; var colorterm = process.env.COLORTERM; @@ -35,8 +77,7 @@ describe('log()', function () { it('should work i guess', function (done) { log(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); if (isLessThanNode12) { expect(stdoutSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -48,8 +89,7 @@ describe('log()', function () { it('should accept formatting', function (done) { log('%s %d %j', 'something', 0.1, { key: 'value' }); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); expect(stdoutSpy.args[1][0]).toEqual('something 0.1 {"key":"value"}\n'); done(); @@ -59,8 +99,7 @@ describe('log()', function () { process.argv.push('--no-color'); log(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + time + '] '); + expectCloseTo(stdoutSpy.args[0][0], false); if (isLessThanNode12) { expect(stdoutSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -76,8 +115,7 @@ describe('log()', function () { process.argv.push('--color'); log(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); if (isLessThanNode12) { expect(stdoutSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -94,8 +132,7 @@ describe('log()', function () { delete process.env.COLORTERM; log(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + time + '] '); + expectCloseTo(stdoutSpy.args[0][0], false); if (isLessThanNode12) { expect(stdoutSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -117,8 +154,7 @@ describe('log.info()', function () { it('should work i guess', function (done) { log.info(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); if (isLessThanNode12) { expect(stdoutSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -130,8 +166,7 @@ describe('log.info()', function () { it('should accept formatting', function (done) { log.info('%s %d %j', 'something', 0.1, { key: 'value' }); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); expect(stdoutSpy.args[1][0]).toEqual('something 0.1 {"key":"value"}\n'); done(); @@ -146,8 +181,7 @@ describe('log.dir()', function () { it('should format an object with util.inspect', function (done) { log.dir({ key: 'value' }); - var time = timestamp('HH:mm:ss'); - expect(stdoutSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); expect(stdoutSpy.args[1][0]).toEqual(util.inspect({ key: 'value' }) + '\n'); done(); @@ -162,8 +196,7 @@ describe('log.warn()', function () { it('should work i guess', function (done) { log.warn(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stderrSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); if (isLessThanNode12) { expect(stderrSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -175,8 +208,7 @@ describe('log.warn()', function () { it('should accept formatting', function (done) { log.warn('%s %d %j', 'something', 0.1, { key: 'value' }); - var time = timestamp('HH:mm:ss'); - expect(stderrSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); expect(stderrSpy.args[1][0]).toEqual('something 0.1 {"key":"value"}\n'); done(); @@ -191,8 +223,7 @@ describe('log.error()', function () { it('should work i guess', function (done) { log.error(1, 2, 3, 4, 'five'); - var time = timestamp('HH:mm:ss'); - expect(stderrSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); if (isLessThanNode12) { expect(stderrSpy.args[1][0]).toEqual("1 2 3 4 'five'\n"); } else { @@ -204,8 +235,7 @@ describe('log.error()', function () { it('should accept formatting', function (done) { log.error('%s %d %j', 'something', 0.1, { key: 'value' }); - var time = timestamp('HH:mm:ss'); - expect(stderrSpy.args[0][0]).toEqual('[' + gray(time) + '] '); + expectCloseTo(stdoutSpy.args[0][0], true); expect(stderrSpy.args[1][0]).toEqual('something 0.1 {"key":"value"}\n'); done();