All files / src/logger/emitter sink.ts

100% Statements 13/13
100% Branches 5/5
100% Functions 1/1
100% Lines 13/13

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 86 87 88 89                                                                                                                                                      1x 80x 80x 80x 80x 80x 7x 7x 80x 7x 7x 80x 80x  
import type { Writable } from 'type-fest';
 
import type { LogLevel } from '../definition.ts';
 
/**
 * Defines the interface for log sinks - destinations where log entries are written.
 *
 * A log sink is the core abstraction for where logs are sent. It can represent console output, files, network
 * endpoints, or any other destination. The optional flush and close methods allow for proper resource management and
 * buffering control.
 */
export type LogSink = {
  /**
   * The main sink function that receives and processes log entries
   */
  readonly sink: (level: LogLevel, message: string, args?: readonly unknown[]) => void;
 
  /**
   * Optional method to flush any buffered entries
   */
  readonly flush?: () => void | Promise<void>;
 
  /**
   * Optional method to clean up resources when the sink is no longer needed
   */
  readonly close?: () => void | Promise<void>;
};
 
/**
 * Converts a sink function into a basic LogSink object.
 *
 * @example Basic conversion
 *
 * ```ts
 * import { emitter } from 'emitnlog/logger';
 *
 * const basicSink = emitter.asLogSink((level, message, args) => {
 *   console.log(`[${level}] ${message}`, ...args);
 * });
 * ```
 *
 * @param sink The sink function to wrap
 * @returns A LogSink object with only the sink function
 */
export function asLogSink(sink: LogSink['sink']): LogSink;
/**
 * Converts a sink function into a LogSink object with flush and close methods.
 *
 * The returned LogSink will have the same flush and close method types as provided in the options (synchronous or
 * asynchronous).
 *
 * @example With flush and close methods
 *
 * ```ts
 * const fileBuffer: string[] = [];
 *
 * const fileSink = asLogSink((level, message) => fileBuffer.push(`[${level}] ${message}`), {
 *   flush: () => {
 *     fs.writeFileSync('log.txt', fileBuffer.join('\n'));
 *     fileBuffer.length = 0;
 *   },
 *   close: () => {
 *     // Clean up resources
 *   },
 * });
 * ```
 *
 * @param sink The sink function to wrap
 * @param options Flush and close methods to add
 * @returns A LogSink object with the provided flush and close methods
 */
export function asLogSink<F extends LogSink['flush'], C extends LogSink['close']>(
  sink: LogSink['sink'],
  options: { flush?: F; close?: C },
): LogSink & { flush: F; close: C };
export function asLogSink(
  sink: LogSink['sink'],
  options?: { flush?: LogSink['flush']; close?: LogSink['close'] },
): LogSink {
  const logSink: Writable<LogSink> = { sink };
  if (options?.flush) {
    logSink.flush = options.flush;
  }
  if (options?.close) {
    logSink.close = options.close;
  }
  return logSink;
}