diff --git a/example.ts b/example.ts index 21e4b35..a23cc35 100644 --- a/example.ts +++ b/example.ts @@ -15,7 +15,7 @@ class User { function example(oe: OnEmitFn) { let user = new User(); - let scope = diary('example', oe); + let scope = diary(oe); scope('log', 'this is a log message'); scope('info', 'this is an info message'); @@ -31,9 +31,6 @@ function example(oe: OnEmitFn) { scope('info', 'this {user} exists', { user }); scope('info', 'we call that user {name} with {id}', user); - - scope = diary(oe); - scope('debug', 'sometimes we do not want a scope name'); } console.log('============ PRETTY ============\n'); @@ -47,7 +44,7 @@ console.log('NOTE: we omit the level, as that is presented in the DevTools.\n'); example(browser); console.log('\n\n============ CLEF (custom) ============\n'); -example((name, level, message, props) => { +example((level, message, props) => { let event = { '@t': new Date().toISOString(), '@l': level, diff --git a/src/mod.test.ts b/src/mod.test.ts index f538f74..133b6b4 100644 --- a/src/mod.test.ts +++ b/src/mod.test.ts @@ -8,7 +8,7 @@ Deno.test('api', () => { assertInstanceOf(lib.diary, Function); let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); assertInstanceOf(log, Function); log('info', 'hello {name}', { name: 'world' }); // @ts-expect-error - wrong type "name" should be "foo" @@ -17,59 +17,50 @@ Deno.test('api', () => { Deno.test('calls onEmit', () => { let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); log('info', 'hello', { name: 'world' }); assertSpyCall(emit, 0, { - args: ['test', 'info', 'hello', { name: 'world' }], + args: ['info', 'hello', { name: 'world' }], }); }); Deno.test('calls onEmit for every log', () => { let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); log('info', 'hello', { name: 'world' }); log('debug', 'hello {phrase}', { phrase: 'world' }); assertSpyCall(emit, 0, { - args: ['test', 'info', 'hello', { name: 'world' }], + args: ['info', 'hello', { name: 'world' }], }); assertSpyCall(emit, 1, { - args: ['test', 'debug', 'hello {phrase}', { phrase: 'world' }], + args: ['debug', 'hello {phrase}', { phrase: 'world' }], }); }); Deno.test('calls with correct level', () => { let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); let i = 0; for (let level of ['log', 'debug', 'info', 'warn', 'error', 'fatal']) { log(level as Level, 'hello', { name: 'world' }); assertSpyCall(emit, i++, { - args: ['test', level, 'hello', { name: 'world' }], + args: [level, 'hello', { name: 'world' }], }); } }); -Deno.test('onEmit retains its `this` context', () => { - let emit = spy(); - let log = lib.diary('test', emit); - log('info', 'hello', { name: 'world' }); - assertSpyCall(emit, 0, { - self: emit, - }); -}); - Deno.test('should allow anything as prop value', () => { class Test {} let t = new Test(); let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); log('info', 'hello {phrase}', { phrase: t }); assertSpyCall(emit, 0, { - args: ['test', 'info', 'hello {phrase}', { phrase: t }], + args: ['info', 'hello {phrase}', { phrase: t }], }); }); @@ -81,7 +72,7 @@ Deno.test('should allow anything as prop', () => { let t = new Test(); let emit = spy(); - let log = lib.diary('test', emit); + let log = lib.diary(emit); log('info', 'hello {phrase}', t); log( @@ -92,6 +83,6 @@ Deno.test('should allow anything as prop', () => { ); assertSpyCall(emit, 0, { - args: ['test', 'info', 'hello {phrase}', t], + args: ['info', 'hello {phrase}', t], }); }); diff --git a/src/mod.ts b/src/mod.ts index 530b3b6..32ae499 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -1,4 +1,4 @@ -import type { Pretty, Props, Dict } from './util.ts'; +import type { Dict, Pretty, Props } from './util.ts'; export type Level = 'log' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; @@ -8,24 +8,16 @@ export interface OnEmitFn { (level: Level, message: string, props?: object | undefined): any; } -export interface LogFn { - , keyof Ctx>>> ( +export interface LogFn { + , keyof Ctx>>>( level: Level, template: T, ...args: keyof Params extends never ? [] : Params extends object ? [properties: Params] : [] ): void; } -export function diary(onEmit: OnEmitFn, ctx?: Ctx): LogFn { +export function diary(onEmit: OnEmitFn, ctx?: Ctx): LogFn { return function log(level, message, props) { - onEmit(level, message, {...ctx, ...props}); + onEmit(level, message, ctx, props); } as LogFn; } - -let s = diary(() => {}, { foo: 'bar'}); -s('info', 'hello'); -s('info', 'hello {foo}'); -s('info', 'hello {foo} {phrase}', { - phrase: 'world', -}); - diff --git a/src/output.console.ts b/src/output.console.ts index ec35a45..5e0fa9a 100644 --- a/src/output.console.ts +++ b/src/output.console.ts @@ -12,8 +12,8 @@ const LEVELS = { fatal: '✗ fatal ' as const, } as const; -function log(out: string, name: string | undefined, level: Level, message: string, props?: object) { - if (name) out += `[${name}] `; +function log(out: string, level: Level, message: string, props?: object) { + //if (name) out += `[${name}] `; let args: unknown[] = []; out += interpolate(message, props, (value) => { @@ -25,25 +25,22 @@ function log(out: string, name: string | undefined, level: Level, message: strin } export function browser( - name: string | undefined, level: Level, message: string, props?: object | undefined, ) { - log('', name, level, message, props); + log('', level, message, props); } export function plain( - name: string | undefined, level: Level, message: string, props?: object | undefined, ) { - log(LEVELS[level], name, level, message, props); + log(LEVELS[level], level, message, props); } export function pretty( - name: string | undefined, level: Level, message: string, props?: object | undefined, @@ -55,5 +52,5 @@ export function pretty( if (level === 'error') l = red(l); if (level === 'fatal') l = bold(red(l)); - log(l, name, level, message, props); + log(l, level, message, props); } diff --git a/src/stream.test.ts b/src/stream.test.ts index f63da1c..40db017 100644 --- a/src/stream.test.ts +++ b/src/stream.test.ts @@ -9,7 +9,7 @@ Deno.test('api', () => { Deno.test('streams', async () => { let events: lib.LogEvent[] = []; - let log = stream.diary('test', async (stream) => { + let log = stream.diary(async (stream) => { assertInstanceOf(stream, ReadableStream); for await (let event of stream) events.push(event); }); @@ -20,7 +20,7 @@ Deno.test('streams', async () => { await delay(1); assertEquals(events, [ - ['test', 'info', 'hello', { name: 'world' }], - ['test', 'debug', 'hello', { name: 'world' }], + ['info', 'hello', { name: 'world' }], + ['debug', 'hello', { name: 'world' }], ]); }); diff --git a/src/stream.ts b/src/stream.ts index bc23158..4abedca 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -1,13 +1,16 @@ import * as lib from './mod.ts'; -export function diary(name: string, cb: (r: ReadableStream) => any): lib.LogFn { +export function diary( + cb: (r: ReadableStream) => any, + ctx?: Ctx, +): lib.LogFn { let stream = new TransformStream(); let writer = stream.writable.getWriter(); cb(stream.readable); return lib.diary( - name, function () { writer.write(Array.from(arguments) as lib.LogEvent); }, + ctx, ); } diff --git a/src/using.test.ts b/src/using.test.ts index 1f8c0e0..6a58fd3 100644 --- a/src/using.test.ts +++ b/src/using.test.ts @@ -11,7 +11,7 @@ Deno.test('calls onEmit', () => { let emit = spy(); { - using log = lib.diary('test', emit); + using log = lib.diary(emit); log('info', 'hello {name}', { name: 'world' }); log('debug', 'hello {name}', { name: 'world' }); } @@ -19,8 +19,8 @@ Deno.test('calls onEmit', () => { assertSpyCall(emit, 0, { args: [ [ - ['test', 'info', 'hello {name}', { name: 'world' }], - ['test', 'debug', 'hello {name}', { name: 'world' }], + ['info', 'hello {name}', { name: 'world' }], + ['debug', 'hello {name}', { name: 'world' }], ], ], }); @@ -30,7 +30,7 @@ Deno.test('allows async disposal', async () => { let emit = spy(() => delay(1)); { - await using log = lib.diary('test', emit); + await using log = lib.diary(emit); log('info', 'hello {name}', { name: 'world' }); log('debug', 'hello {name}', { name: 'world' }); } @@ -38,8 +38,8 @@ Deno.test('allows async disposal', async () => { assertSpyCall(emit, 0, { args: [ [ - ['test', 'info', 'hello {name}', { name: 'world' }], - ['test', 'debug', 'hello {name}', { name: 'world' }], + ['info', 'hello {name}', { name: 'world' }], + ['debug', 'hello {name}', { name: 'world' }], ], ], }); diff --git a/src/using.ts b/src/using.ts index b45161c..0779d9c 100644 --- a/src/using.ts +++ b/src/using.ts @@ -1,18 +1,21 @@ import * as lib from './mod.ts'; -export interface LogFn extends lib.LogFn { +export interface LogFn extends lib.LogFn { [Symbol.dispose](): void; } -export function diary(name: string, flush: (events: lib.LogEvent[]) => any): LogFn { +export function diary( + flush: (events: lib.LogEvent[]) => any, + ctx?: Ctx, +): LogFn { const events: lib.LogEvent[] = []; let log = lib.diary( - name, function () { events.push(Array.from(arguments) as lib.LogEvent); }, - ) as LogFn; + ctx, + ) as LogFn; log[Symbol.dispose] = function () { return flush(events); };