All files / src/logger/emitter emitter-logger.ts

100% Statements 29/29
100% Branches 9/9
100% Functions 6/6
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85    1x                                                                                               1x 310x 310x 310x 310x 310x 310x   310x 310x   310x 310x   310x 310x 310x 310x 310x 310x   310x 72x 72x   310x 310x 310x 310x   310x 832x 832x 310x  
import type { Logger, LogLevel } from '../definition.ts';
import type { BaseLoggerOptions } from '../implementation/base-logger.ts';
import { BaseLogger } from '../implementation/base-logger.ts';
import type { LogSink } from './sink.ts';
 
/**
 * Creates a logger that emits entries to the specified log sink.
 *
 * This is the core logger factory function that powers all other logger creation functions. It accepts either a sink
 * function directly or a full LogSink object with optional flush/close methods.
 *
 * @example Basic usage with sink function
 *
 * ```ts
 * import { emitter } from 'emitnlog/logger';
 *
 * const logger = emitter.createLogger('info', (level, message, args) => {
 *   console.log(`[${level.toUpperCase()}] ${message}`, ...args);
 * });
 *
 * logger.i`Hello world`;
 * ```
 *
 * @example Usage with full LogSink object
 *
 * ```ts
 * import { emitter } from 'emitnlog/logger';
 *
 * const sink = emitter.consoleLogSink();
 * const logger = emitter.createLogger('info', sink);
 * logger.i`Hello world`;
 * ```
 *
 * @param level The minimum log level or a function that returns the level
 * @param logSink The sink function or LogSink object to emit entries to
 * @param options Additional logger configuration options
 * @returns A logger instance that emits to the specified sink
 */
export function createLogger(
  level: LogLevel | 'off' | (() => LogLevel | 'off'),
  logSink: LogSink['sink'],
  options?: BaseLoggerOptions,
): Logger;
 
export function createLogger<S extends LogSink>(
  level: LogLevel | 'off' | (() => LogLevel | 'off'),
  logSink: S,
  options?: BaseLoggerOptions,
): Exclude<Logger, 'flush' | 'close'> & Pick<S, 'flush' | 'close'>;
 
export function createLogger(
  level: LogLevel | 'off' | (() => LogLevel | 'off'),
  logSink: LogSink | LogSink['sink'],
  options?: BaseLoggerOptions,
): Logger {
  return new EmitterLogger(level, logSink, options);
}
 
class EmitterLogger extends BaseLogger {
  private readonly logSink: LogSink;
 
  public readonly flush: (() => void | Promise<void>) | undefined;
  public readonly close: (() => void | Promise<void>) | undefined;
 
  public constructor(
    level: LogLevel | 'off' | (() => LogLevel | 'off'),
    logSink: LogSink | LogSink['sink'],
    options?: BaseLoggerOptions,
  ) {
    super(level, options);
 
    if (typeof logSink === 'function') {
      logSink = { sink: logSink };
    }
 
    this.logSink = logSink;
    this.flush = logSink.flush && (() => logSink.flush?.());
    this.close = logSink.close && (() => logSink.close?.());
  }
 
  protected override emit(level: LogLevel, message: string, args: readonly unknown[]): void {
    this.logSink.sink(level, message, args);
  }
}