From 8fba2b37fbbcbb0c002933c9c5b9a8530a62bfd9 Mon Sep 17 00:00:00 2001 From: Mike North Date: Thu, 2 Aug 2018 12:11:16 -0700 Subject: [PATCH] feat: tagged logging --- src/index.ts | 53 ++++++++++++++++++++++++++++++++++++- test/tagged-logging-test.ts | 34 ++++++++++++++++++++++++ test/test-helpers.ts | 42 ++++++++++++++--------------- 3 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 test/tagged-logging-test.ts diff --git a/src/index.ts b/src/index.ts index c7ee996..f4ab674 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,8 @@ export type ILoggerInstance = Printer & { [K in keyof typeof COLORS]: ILoggerInstance } & { txt(str: string): ILoggerInstance + pushPrefix(str: string): ILoggerInstance + popPrefix(): ILoggerInstance }; // tslint:disable-next-line:interface-name export interface ILogger { @@ -49,6 +51,9 @@ class Logger { // An array of current styles private stylesInProgress: string[] = []; + // An array of prefixes that go at the beginning of each message + private prefixesAndStyles: Array<[string, string]> = []; + // An array of message & their associated styles private msgsAndStyles: Array<[string, string]> = []; @@ -63,6 +68,48 @@ class Logger { this.setupStyles(); } + /** + * Adds a prefix that will be applied to all messages. + * This is useful for indicating the context in which a message is logged, + * without forcing developers to "re-state" that context over and over. + * + * @example + * ```ts + * const logger = new Logger(); + * + * function fooFunction() { + * logger.pushPrefix('foo'); + * ... + * logger.log('hello'); + * logger.log('world'); + * ... + * logger.popPrefix(); + * } + * + * logger.log('begin'); // "begin" + * fooFunction(); // "[foo]: hello" + * // "[foo]: world" + * logger.log('end'); // "end" + * + * ``` + * @param name the name of the tag + */ + pushPrefix(name: string) { + this.prefixesAndStyles.push([name, this.stylesInProgress.join('')]); + this.stylesInProgress = []; + return this; + } + + /** + * Remove the most recently added prefix from the logger + * + * @see {Logger.pushPrefix} + */ + popPrefix() { + this.prefixesAndStyles.pop(); + return this; + } + css(style: string) { this.stylesInProgress.push(style); return this; @@ -138,11 +185,15 @@ class Logger { let logFunction = this.printer[functionName]; let allMsgs = ''; let allStyles: string[] = []; + for (let [msg, style] of this.prefixesAndStyles) { + allMsgs += `%c[${msg}]`; + allStyles.push(style); + } + if (allMsgs.length > 0) allMsgs += ': '; for (let [msg, style] of this.msgsAndStyles) { allMsgs += `%c ${msg}`; allStyles.push(style); } - logFunction(allMsgs, ...allStyles); this.msgsAndStyles = []; } diff --git a/test/tagged-logging-test.ts b/test/tagged-logging-test.ts new file mode 100644 index 0000000..e1790f8 --- /dev/null +++ b/test/tagged-logging-test.ts @@ -0,0 +1,34 @@ +import Logger from 'bite-log'; +import { logCountAssert, makeTestPrinter } from './test-helpers'; + +QUnit.module('Tagged logging'); + +QUnit.test( + 'Pushing a tag results in the log mesages being prefixed', + assert => { + const printer = makeTestPrinter(); + const logger = new Logger(4, printer); + logger.log('hello'); // "hello" + logger.log('world'); // "world" + logger.pushPrefix('foo'); + logger.log('goodbye'); // "[foo]: goodbye" + logger.log('mars'); // "[foo]: mars" + logger.pushPrefix('bar'); + logger.log('(and saturn!)'); // "[foo][bar]: (and saturn)!" + logger.popPrefix(); + logger.popPrefix(); + logger.log('but not pluto'); // "but not pluto" + logCountAssert( + { message: 'after logging four things', assert, printer }, + { l: 6 } + ); + const logs = printer.messages.log; + assert.ok(logs[0].join('').indexOf('foo') < 0, 'First message has no "foo" tag'); + assert.ok(logs[1].join('').indexOf('foo') < 0, 'Second message has no "foo" tag'); + assert.ok(logs[2].join('').indexOf('foo') >= 0, 'Third message has a "foo" tag'); + assert.ok(logs[3].join('').indexOf('foo') >= 0, 'Fourth message has a "foo" tag'); + assert.ok(logs[4].join('').indexOf('foo') >= 0, 'Fifth message has a "foo" tag'); + assert.ok(logs[4].join('').indexOf('bar') >= 0, 'Fifth message has a "bar" tag'); + assert.ok(logs[5].join('').indexOf('foo') < 0, 'Sixth message has no "foo" tag'); + } +); diff --git a/test/test-helpers.ts b/test/test-helpers.ts index 9fe4f6a..5383bb4 100644 --- a/test/test-helpers.ts +++ b/test/test-helpers.ts @@ -29,35 +29,35 @@ export function logCountAssert( message, assert, printer - }: { message: string; assert: Assert; printer: Printer }, + }: { message: string; assert: Assert; printer: Printer; }, { e, w, l, d }: { e?: number; w?: number; l?: number; d?: number } ) { if (typeof e !== 'undefined') { - assert.equal( - (printer as any).messages.error.length, - e, - `${message}: ${e} error(s) were logged` - ); + assert.equal( + (printer as any).messages.error.length, + e, + `${message}: ${e} error(s) were logged` + ); } if (typeof w !== 'undefined') { - assert.equal( - (printer as any).messages.warn.length, - w, - `${message}: ${w} warning(s) was logged` - ); + assert.equal( + (printer as any).messages.warn.length, + w, + `${message}: ${w} warning(s) was logged` + ); } if (typeof d !== 'undefined') { - assert.equal( - (printer as any).messages.debug.length, - d, - `${message}: ${d} debug(s) were logged` - ); + assert.equal( + (printer as any).messages.debug.length, + d, + `${message}: ${d} debug(s) were logged` + ); } if (typeof l !== 'undefined') { - assert.equal( - (printer as any).messages.log.length, - l, - `${message}: ${l} log(s) were logged` - ); + assert.equal( + (printer as any).messages.log.length, + l, + `${message}: ${l} log(s) were logged` + ); } }