128 lines · 3.6 KB · TypeScript
RawDownload
// CRITICAL/** * Logging levels. */import { createWriteStream, mkdirSync } from "node:fs";import type { WriteStream } from "node:fs";import { dirname } from "node:path"; export type LogLevel = "debug" | "info" | "warn" | "error"; export interface LoggerOptions {  filePath?: string;  /**   * Called after formatting a log line (best-effort, fire-and-forget).   * Useful for pushing logs to SSE channels in addition to console/disk.   */  onLine?: (line: string, meta: { level: LogLevel }) => void | Promise<void>;} /** * Logger contract. */export interface Logger {  debug: (message: string, details?: Record<string, unknown>) => void;  info: (message: string, details?: Record<string, unknown>) => void;  warn: (message: string, details?: Record<string, unknown>) => void;  error: (message: string, details?: Record<string, unknown>) => void;} /** * Create a logger with a minimum level. * @param level - Minimum log level. * @param options - Optional sinks (file, callbacks). * @returns Logger instance. */export const createLogger = (level: LogLevel, options: LoggerOptions = {}): Logger => {  const stream = ((): WriteStream | null => {    if (!options.filePath) return null;    try {      mkdirSync(dirname(options.filePath), { recursive: true });      return createWriteStream(options.filePath, { flags: "a" });    } catch {      return null;    }  })();   const priority: Record<LogLevel, number> = {    debug: 10,    info: 20,    warn: 30,    error: 40,  };   const shouldLog = (target: LogLevel): boolean => priority[target] >= priority[level];   const format = (message: string, details?: Record<string, unknown>): string => {    if (!details || Object.keys(details).length === 0) {      return message;    }    return `${message} ${JSON.stringify(details)}`;  };   const toFileLine = (target: LogLevel, message: string, details?: Record<string, unknown>): string => {    const ts = new Date().toISOString();    const base = format(message, details);    return `${ts} ${target.toUpperCase()} ${base}\n`;  };   const tryWrite = (target: LogLevel, message: string, details?: Record<string, unknown>): void => {    const line = toFileLine(target, message, details);     if (stream) {      try {        stream.write(line);      } catch {        // best-effort      }    }     if (options.onLine) {      try {        void options.onLine(line.trimEnd(), { level: target });      } catch {        // best-effort      }    }  };   return {    debug: (message, details): void => {      if (shouldLog("debug")) {        console.debug(format(message, details));        tryWrite("debug", message, details);      }    },    info: (message, details): void => {      if (shouldLog("info")) {        console.info(format(message, details));        tryWrite("info", message, details);      }    },    warn: (message, details): void => {      if (shouldLog("warn")) {        console.warn(format(message, details));        tryWrite("warn", message, details);      }    },    error: (message, details): void => {      if (shouldLog("error")) {        console.error(format(message, details));        tryWrite("error", message, details);      }    },  };}; /** * Resolve the log level from environment variables. * @param fallback - Default log level. * @returns Resolved log level. */export const resolveLogLevel = (fallback: LogLevel): LogLevel => {  const raw = process.env["VLLM_STUDIO_LOG_LEVEL"]?.toLowerCase();  if (raw === "debug" || raw === "info" || raw === "warn" || raw === "error") {    return raw;  }  return fallback;};