diff --git a/src/index.ts b/src/index.ts index 563d2f7..145e8f5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,8 @@ export type ILoggerInstance = Printer & { [K in keyof typeof COLOR_STYLES]: 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/src/styles.ts b/src/styles.ts index 1200b33..0f5f843 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -1,6 +1,6 @@ import X11_COLORS from './colors'; -interface StyleObj { [k: string]: string; }; +interface StyleObj { [k: string]: string; } const COLOR_STYLES: StyleObj = { }; for (let c of X11_COLORS) { @@ -15,6 +15,6 @@ for (let c of X11_COLORS) { // }; export default { - ...COLOR_STYLES, + ...COLOR_STYLES // , // ...fontStyles }; 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'); + } +);