{"version":3,"sources":["/home/runner/work/loglayer/loglayer/packages/transports/log-file-rotation/dist/index.cjs","../src/LogFileRotationTransport.ts"],"names":[],"mappings":"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","file":"/home/runner/work/loglayer/loglayer/packages/transports/log-file-rotation/dist/index.cjs","sourcesContent":[null,"import type { WriteStream } from \"node:fs\";\nimport { createReadStream, createWriteStream, writeFileSync } from \"node:fs\";\nimport { access, unlink } from \"node:fs/promises\";\nimport { pipeline } from \"node:stream/promises\";\nimport { createGzip } from \"node:zlib\";\nimport type { LogLayerTransportParams, LoggerlessTransportConfig } from \"@loglayer/transport\";\nimport { LoggerlessTransport } from \"@loglayer/transport\";\nimport FileStreamRotator from \"file-stream-rotator\";\n\ninterface FileStreamRotatorOptions {\n  filename: string;\n  frequency?: string;\n  verbose?: boolean;\n  date_format?: string;\n  size?: string;\n  max_logs?: string;\n  audit_file?: string;\n  end_stream?: boolean;\n  extension?: string;\n  create_symlink?: boolean;\n  symlink_name?: string;\n  utc?: boolean;\n  audit_hash_type?: \"md5\" | \"sha256\";\n  file_options?: {\n    flags?: string;\n    encoding?: string;\n    mode?: number;\n  };\n}\n\nexport interface LogFileRotationCallbacks {\n  /**\n   * Called when a log file is rotated\n   * @param oldFile - The path to the old log file\n   * @param newFile - The path to the new log file\n   */\n  onRotate?: (oldFile: string, newFile: string) => void;\n  /**\n   * Called when a new log file is created\n   * @param newFile - The path to the new log file\n   */\n  onNew?: (newFile: string) => void;\n  /**\n   * Called when a log file is opened\n   */\n  onOpen?: () => void;\n  /**\n   * Called when a log file is closed\n   */\n  onClose?: () => void;\n  /**\n   * Called when an error occurs\n   * @param error - The error that occurred\n   */\n  onError?: (error: Error) => void;\n  /**\n   * Called when the stream is finished\n   */\n  onFinish?: () => void;\n  /**\n   * Called when a log file is removed due to retention policy\n   * @param info - Information about the removed log file\n   */\n  onLogRemoved?: (info: { date: number; name: string; hash: string }) => void;\n}\n\nexport interface LogFileRotationFieldNames {\n  /**\n   * Field name for the log level\n   * @default \"level\"\n   */\n  level?: string;\n  /**\n   * Field name for the log message\n   * @default \"message\"\n   */\n  message?: string;\n  /**\n   * Field name for the timestamp\n   * @default \"timestamp\"\n   */\n  timestamp?: string;\n}\n\nexport interface LogFileRotationLevelMap {\n  /**\n   * Mapping for the 'fatal' log level\n   * @example 60 or \"FATAL\"\n   */\n  fatal?: string | number;\n  /**\n   * Mapping for the 'error' log level\n   * @example 50 or \"ERROR\"\n   */\n  error?: string | number;\n  /**\n   * Mapping for the 'warn' log level\n   * @example 40 or \"WARN\"\n   */\n  warn?: string | number;\n  /**\n   * Mapping for the 'info' log level\n   * @example 30 or \"INFO\"\n   */\n  info?: string | number;\n  /**\n   * Mapping for the 'debug' log level\n   * @example 20 or \"DEBUG\"\n   */\n  debug?: string | number;\n  /**\n   * Mapping for the 'trace' log level\n   * @example 10 or \"TRACE\"\n   */\n  trace?: string | number;\n}\n\nexport interface LogFileRotationBatchConfig {\n  /**\n   * Maximum number of log entries to queue before writing.\n   * Default: 1000\n   */\n  size?: number;\n  /**\n   * Maximum time in milliseconds to wait before writing queued logs.\n   * Default: 5000 (5 seconds)\n   */\n  timeout?: number;\n}\n\nexport interface LogFileRotationTransportConfig extends LoggerlessTransportConfig {\n  /**\n   * The filename pattern to use for the log files.\n   * Supports date format using numerical values.\n   * Example: \"./logs/application-%DATE%.log\"\n   */\n  filename: string;\n  /**\n   * Static data to be included in every log entry.\n   * Can be either:\n   * - A function that returns an object containing static data\n   * - A direct object containing static data\n   *\n   * The data will be merged with the log entry before any other data.\n   * If using a function, it will be called for each log entry.\n   * @example\n   * ```typescript\n   * // Using a function\n   * staticData: () => ({\n   *   hostname: hostname(),\n   *   pid: process.pid\n   * })\n   *\n   * // Using an object\n   * staticData: {\n   *   hostname: hostname(),\n   *   pid: process.pid\n   * }\n   * ```\n   */\n  staticData?: (() => Record<string, any>) | Record<string, any>;\n  /**\n   * The frequency of rotation. Can be:\n   * - 'daily' for daily rotation\n   * - 'date' for rotation on date format change\n   * - '[1-30]m' for rotation every X minutes\n   * - '[1-12]h' for rotation every X hours\n   */\n  frequency?: string;\n  /**\n   * The date format to use in the filename.\n   * Uses single characters for each date component:\n   * - 'Y' for full year\n   * - 'M' for month\n   * - 'D' for day\n   * - 'H' for hour\n   * - 'm' for minutes\n   * - 's' for seconds\n   *\n   * Common patterns:\n   * - For daily rotation: use \"YMD\" (creates files like app-20240117.log)\n   * - For hourly/minute rotation: use \"YMDHm\" (creates files like app-202401171430.log)\n   *\n   * @default \"YMD\"\n   */\n  dateFormat?: string;\n  /**\n   * The size at which to rotate.\n   * Examples: \"10M\", \"100K\", \"100B\"\n   * If frequency is specified, this will be ignored.\n   */\n  size?: string;\n  /**\n   * Maximum number of logs to keep.\n   * Can be a number of files or days (e.g., \"10d\" for 10 days)\n   */\n  maxLogs?: string | number;\n  /**\n   * Location to store the log audit file.\n   * If not set, it will be stored in the root of the application.\n   */\n  auditFile?: string;\n  /**\n   * File extension to be appended to the filename.\n   * Useful when using size restrictions as the rotation adds a count at the end.\n   */\n  extension?: string;\n  /**\n   * Create a tailable symlink to the current active log file.\n   * Default: false\n   */\n  createSymlink?: boolean;\n  /**\n   * Name to use when creating the symbolic link.\n   * Default: 'current.log'\n   */\n  symlinkName?: string;\n  /**\n   * Use UTC time for date in filename.\n   * Default: false\n   */\n  utc?: boolean;\n  /**\n   * Use specified hashing algorithm for audit.\n   * Default: 'md5'\n   * Use 'sha256' for FIPS compliance.\n   */\n  auditHashType?: \"md5\" | \"sha256\";\n  /**\n   * File mode to be used when creating log files.\n   * Default: 0o640 (user read/write, group read, others none)\n   */\n  fileMode?: number;\n  /**\n   * Options passed to the file stream.\n   * See: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options\n   */\n  fileOptions?: {\n    flags?: string;\n    encoding?: string;\n    mode?: number;\n  };\n  /**\n   * Event callbacks for various file stream events\n   */\n  callbacks?: LogFileRotationCallbacks;\n  /**\n   * Custom field names for the log entry JSON\n   * Default: { level: \"level\", message: \"message\", data: \"data\", timestamp: \"timestamp\" }\n   */\n  fieldNames?: LogFileRotationFieldNames;\n  /**\n   * Delimiter between log entries.\n   * Default: \"\\n\"\n   */\n  delimiter?: string;\n  /**\n   * Custom function to generate timestamps for log entries.\n   * Can return either a string (e.g., ISO string) or a number (e.g., Unix timestamp)\n   * If not provided, defaults to new Date().toISOString()\n   */\n  timestampFn?: () => string | number;\n  /**\n   * Custom mapping for log levels.\n   * Each log level can be mapped to either a string or number.\n   * Example: { error: 50, warn: 40, info: 30, debug: 20, trace: 10, fatal: 60 }\n   * Example: { error: \"ERROR\", warn: \"WARN\", info: \"INFO\", debug: \"DEBUG\", trace: \"TRACE\", fatal: \"FATAL\" }\n   */\n  levelMap?: LogFileRotationLevelMap;\n  /**\n   * Whether to compress rotated log files using gzip.\n   * When enabled, rotated files will be compressed with .gz extension.\n   * Default: false\n   */\n  compressOnRotate?: boolean;\n  /**\n   * Whether to enable verbose mode in the underlying file-stream-rotator.\n   * When enabled, the rotator will log detailed information about its operations.\n   * Default: false\n   */\n  verbose?: boolean;\n  /**\n   * Batch processing configuration.\n   * If defined, batch processing will be enabled.\n   * When batching is enabled, logs are queued in memory and written to disk in batches.\n   * Queued logs are automatically flushed in the following situations:\n   * - When the batch size is reached\n   * - When the batch timeout is reached\n   * - When the transport is disposed\n   * - When the process exits (including SIGINT and SIGTERM signals)\n   */\n  batch?: LogFileRotationBatchConfig;\n}\n\n/**\n * A transport that writes logs to rotating files with support for time-based and size-based rotation.\n * Features include:\n * - Automatic log file rotation based on time (hourly, daily) or size\n * - Support for date patterns in filenames using numerical values (YYYY, MM, DD, etc.)\n * - Size-based rotation with support for KB, MB, and GB units\n * - Compression of rotated log files using gzip\n * - Maximum file count or age-based retention\n * - Automatic cleanup of old log files\n * - Batch processing of logs for improved performance\n * - Safe handling of process termination signals\n *\n * Each instance must have a unique filename to prevent race conditions.\n * If you need multiple loggers to write to the same file, share the same transport instance between them.\n */\nexport class LogFileRotationTransport extends LoggerlessTransport implements Disposable {\n  /** Registry of active filenames to prevent multiple transports writing to the same file */\n  private static activeFilenames = new Set<string>();\n  /** The current write stream for the log file */\n  private stream: WriteStream;\n  /** Custom field names for log entries */\n  private fieldNames: Required<LogFileRotationFieldNames>;\n  /** Delimiter between log entries */\n  private delimiter: string;\n  /** Function to generate timestamps for log entries */\n  private timestampFn: () => string | number;\n  /** Custom mapping for log levels */\n  private levelMap: LogFileRotationLevelMap;\n  /** Whether to compress rotated files */\n  private compressOnRotate: boolean;\n  /** Whether a file is currently being compressed */\n  private isCompressing: boolean;\n  /** The base filename pattern for log files */\n  private filename: string;\n  /** Static data to be included in every log entry */\n  private staticData?: (() => Record<string, any>) | Record<string, any>;\n  /** Whether batch processing is enabled */\n  private batchEnabled: boolean;\n  /** Maximum number of log entries to queue before writing */\n  private batchSize: number;\n  /** Maximum time in milliseconds to wait before writing queued logs */\n  private batchTimeout: number;\n  /** Queue of log entries waiting to be written */\n  private batchQueue: string[];\n  /** Timer for batch flush timeout */\n  private batchTimer: NodeJS.Timeout | null;\n  /** Whether the transport is being disposed */\n  private isDisposing: boolean;\n  /** Event callbacks for various file stream events */\n  private callbacks?: LogFileRotationCallbacks;\n  /** Frequency of rotation (daily, hourly, etc.) */\n  private frequency?: string;\n  /** Whether to enable verbose mode */\n  private verbose?: boolean;\n  /** Date format for filename patterns */\n  private dateFormat?: string;\n  /** Size threshold for rotation */\n  private size?: string;\n  /** Maximum number of log files to keep */\n  private maxLogs?: string | number;\n  /** Path to the audit file */\n  private auditFile?: string;\n  /** File extension for log files */\n  private extension?: string;\n  /** Whether to create a symlink to current log */\n  private createSymlink?: boolean;\n  /** Name of the symlink file */\n  private symlinkName?: string;\n  /** Whether to use UTC time in filenames */\n  private utc?: boolean;\n  /** Hash algorithm for audit file */\n  private auditHashType?: \"md5\" | \"sha256\";\n  /** Options for file streams */\n  private fileOptions?: {\n    flags?: string;\n    encoding?: string;\n    mode?: number;\n  };\n  /** File mode to be used when creating log files */\n  private fileMode?: number;\n\n  /**\n   * Generates the options for FileStreamRotator consistently across the transport\n   * @returns FileStreamRotatorOptions object\n   * @private\n   */\n  private getRotatorOptions(): FileStreamRotatorOptions {\n    return {\n      filename: this.filename,\n      frequency: this.frequency,\n      verbose: this.verbose ?? false,\n      date_format: this.dateFormat,\n      size: this.size,\n      max_logs: this.maxLogs?.toString(),\n      audit_file: this.auditFile || undefined,\n      end_stream: true,\n      extension: this.extension,\n      create_symlink: this.createSymlink,\n      symlink_name: this.symlinkName,\n      utc: this.utc,\n      audit_hash_type: this.auditHashType,\n      file_options: {\n        flags: \"a\",\n        encoding: \"utf8\",\n        mode: this.fileMode ?? 0o640,\n        ...this.fileOptions,\n      },\n    };\n  }\n\n  /**\n   * Creates a new LogFileRotationTransport instance.\n   * @param params - Configuration options for the transport\n   * @throws {Error} If the filename is already in use by another transport instance\n   */\n  constructor(params: LogFileRotationTransportConfig) {\n    super(params);\n\n    // Check if filename is already in use\n    if (LogFileRotationTransport.activeFilenames.has(params.filename)) {\n      throw new Error(\n        `LogFileRotationTransport: Filename \"${params.filename}\" is already in use by another instance. To use the same file for multiple loggers, share the same transport instance between them.`,\n      );\n    }\n\n    // Register the filename\n    this.filename = params.filename;\n    LogFileRotationTransport.activeFilenames.add(this.filename);\n\n    // Set up field names with defaults\n    this.fieldNames = {\n      level: params.fieldNames?.level ?? \"level\",\n      message: params.fieldNames?.message ?? \"message\",\n      timestamp: params.fieldNames?.timestamp ?? \"timestamp\",\n    };\n\n    // Set up delimiter\n    this.delimiter = params.delimiter ?? \"\\n\";\n\n    // Set up timestamp function\n    this.timestampFn = params.timestampFn ?? (() => new Date().toISOString());\n\n    // Set up level mapping\n    this.levelMap = params.levelMap ?? {};\n\n    // Set up compression\n    this.compressOnRotate = params.compressOnRotate ?? false;\n    this.isCompressing = false;\n\n    // Set up batching\n    this.batchEnabled = !!params.batch;\n    this.batchSize = params.batch?.size ?? 1000;\n    this.batchTimeout = params.batch?.timeout ?? 5000;\n    this.batchQueue = [];\n    this.batchTimer = null;\n    this.isDisposing = false;\n\n    // Store other options\n    this.callbacks = params.callbacks;\n    this.frequency = params.frequency;\n    this.verbose = params.verbose;\n    this.dateFormat = params.dateFormat;\n    this.size = params.size;\n    this.maxLogs = params.maxLogs;\n    this.auditFile = params.auditFile;\n    this.extension = params.extension;\n    this.createSymlink = params.createSymlink;\n    this.symlinkName = params.symlinkName;\n    this.utc = params.utc;\n    this.auditHashType = params.auditHashType;\n    this.fileOptions = params.fileOptions;\n    this.fileMode = params.fileMode;\n    this.staticData = params.staticData;\n\n    // Set up exit handler for flushing\n    if (this.batchEnabled) {\n      // Handle normal process exit\n      process.on(\"beforeExit\", () => {\n        if (!this.isDisposing) {\n          this.flush();\n        }\n      });\n\n      // Handle SIGINT (Ctrl+C) and SIGTERM\n      const handleSignal = (signal: string) => {\n        if (!this.isDisposing) {\n          // Synchronously flush logs to ensure they're written before exit\n          this.flushSync();\n          // Remove the filename from registry\n          LogFileRotationTransport.activeFilenames.delete(this.filename);\n          // Exit with the original signal\n          process.exit(signal === \"SIGINT\" ? 130 : 143);\n        }\n      };\n\n      process.on(\"SIGINT\", () => handleSignal(\"SIGINT\"));\n      process.on(\"SIGTERM\", () => handleSignal(\"SIGTERM\"));\n    }\n\n    // Only create the stream if not in batch mode or if we have logs to write\n    if (!this.batchEnabled) {\n      this.initStream(this.getRotatorOptions());\n    }\n  }\n\n  /**\n   * Initializes the write stream and sets up event listeners.\n   * This is called either immediately if batching is disabled,\n   * or lazily when the first batch needs to be written if batching is enabled.\n   * @param options - Options for the file stream rotator\n   * @private\n   */\n  private initStream(options: FileStreamRotatorOptions): void {\n    // FileStreamRotator.getStream() returns a WriteStream-compatible object\n    this.stream = FileStreamRotator.getStream(options) as unknown as WriteStream;\n\n    // Set up event listeners if callbacks are provided\n    if (this.callbacks) {\n      const { onRotate, onNew, onOpen, onClose, onError, onFinish, onLogRemoved } = this.callbacks;\n\n      // Wrap the onRotate callback to handle compression\n      if (this.compressOnRotate) {\n        this.stream.on(\"rotate\", async (oldFile: string, newFile: string) => {\n          try {\n            this.isCompressing = true;\n            const compressedPath = await this.compressFile(oldFile);\n            await unlink(oldFile);\n            onRotate?.(compressedPath, newFile);\n          } catch (error) {\n            this.callbacks?.onError?.(error as Error);\n          } finally {\n            this.isCompressing = false;\n          }\n        });\n      } else if (onRotate) {\n        this.stream.on(\"rotate\", onRotate);\n      }\n\n      if (onNew) {\n        this.stream.on(\"new\", onNew);\n      }\n      if (onOpen) {\n        this.stream.on(\"open\", onOpen);\n      }\n      if (onClose) {\n        this.stream.on(\"close\", onClose);\n      }\n      if (onError) {\n        this.stream.on(\"error\", onError);\n      }\n      if (onFinish) {\n        this.stream.on(\"finish\", onFinish);\n      }\n      if (onLogRemoved) {\n        this.stream.on(\"logRemoved\", onLogRemoved);\n      }\n    }\n  }\n\n  /**\n   * Generates a unique path for a compressed log file.\n   * If a file with .gz extension already exists, appends timestamp and counter.\n   * @param filePath - The original log file path\n   * @returns The unique path for the compressed file\n   * @private\n   */\n  private async getUniqueCompressedFilePath(filePath: string): Promise<string> {\n    let finalPath = `${filePath}.gz`;\n    let counter = 0;\n\n    try {\n      while (true) {\n        try {\n          await access(finalPath);\n          counter++;\n          finalPath = `${filePath}.${Date.now()}.${counter}.gz`;\n        } catch {\n          break;\n        }\n      }\n    } catch (error) {\n      finalPath = `${filePath}.${Date.now()}.gz`;\n    }\n\n    return finalPath;\n  }\n\n  /**\n   * Compresses a log file using gzip.\n   * @param filePath - Path to the file to compress\n   * @returns Path to the compressed file\n   * @private\n   */\n  private async compressFile(filePath: string): Promise<string> {\n    const gzPath = await this.getUniqueCompressedFilePath(filePath);\n    const gzip = createGzip();\n    const source = createReadStream(filePath);\n    const destination = createWriteStream(gzPath);\n\n    await pipeline(source, gzip, destination);\n    return gzPath;\n  }\n\n  /**\n   * Flushes queued log entries to disk asynchronously.\n   * This is used for normal batch processing operations.\n   * @private\n   */\n  private flush(): void {\n    if (!this.batchEnabled || this.batchQueue.length === 0) {\n      return;\n    }\n\n    if (this.batchTimer) {\n      clearTimeout(this.batchTimer);\n      this.batchTimer = null;\n    }\n\n    // Initialize stream if it hasn't been created yet\n    if (!this.stream) {\n      this.initStream(this.getRotatorOptions());\n    }\n\n    const batchContent = this.batchQueue.join(\"\");\n    this.stream.write(batchContent);\n    this.batchQueue = [];\n  }\n\n  /**\n   * Synchronously flush logs to disk.\n   * This is used during process termination (SIGINT/SIGTERM) to ensure logs are written\n   * before the process exits. This method uses synchronous file I/O to guarantee that\n   * logs are written even during abrupt process termination.\n   * @private\n   */\n  private flushSync(): void {\n    if (!this.batchEnabled || this.batchQueue.length === 0) {\n      return;\n    }\n\n    if (this.batchTimer) {\n      clearTimeout(this.batchTimer);\n      this.batchTimer = null;\n    }\n\n    // Initialize stream if it hasn't been created yet\n    if (!this.stream) {\n      this.initStream(this.getRotatorOptions());\n    }\n\n    const batchContent = this.batchQueue.join(\"\");\n    // Use writeFileSync to ensure logs are written before process exit\n    const rotator = this.stream as unknown as { currentFile: string };\n    if (rotator.currentFile) {\n      writeFileSync(rotator.currentFile, batchContent, { flag: \"a\" });\n    }\n    this.batchQueue = [];\n  }\n\n  /**\n   * Schedules a batch flush operation.\n   * This creates a timer that will flush the batch after the configured timeout.\n   * The timer is unref'd to prevent keeping the process alive.\n   * @private\n   */\n  private scheduleBatchFlush(): void {\n    if (!this.batchTimer && !this.isDisposing) {\n      this.batchTimer = setTimeout(() => {\n        this.flush();\n      }, this.batchTimeout);\n\n      // Prevent timer from keeping the process alive\n      if (this.batchTimer.unref) {\n        this.batchTimer.unref();\n      }\n    }\n  }\n\n  /**\n   * Processes and writes a log entry.\n   * If batching is enabled, the entry is queued and written based on batch settings.\n   * If batching is disabled, the entry is written immediately.\n   * @param params - The log entry parameters\n   * @returns The original messages array\n   */\n  shipToLogger({ logLevel, messages, data, hasData }: LogLayerTransportParams) {\n    const logEntry = {\n      [this.fieldNames.level]: this.levelMap[logLevel as keyof LogFileRotationLevelMap] ?? logLevel,\n      [this.fieldNames.message]: messages.join(\" \") || \"\",\n      [this.fieldNames.timestamp]: this.timestampFn(),\n      ...(this.staticData ? (typeof this.staticData === \"function\" ? this.staticData() : this.staticData) : {}),\n      ...(hasData ? data : {}),\n    };\n\n    const logString = `${JSON.stringify(logEntry)}${this.delimiter}`;\n\n    if (this.batchEnabled) {\n      this.batchQueue.push(logString);\n\n      if (this.batchQueue.length >= this.batchSize) {\n        this.flush();\n      } else {\n        this.scheduleBatchFlush();\n      }\n    } else {\n      this.stream.write(logString);\n    }\n\n    return messages;\n  }\n\n  /**\n   * Disposes of the transport, cleaning up resources and flushing any remaining logs.\n   * This method:\n   * 1. Prevents new batch flushes from being scheduled\n   * 2. Cancels any pending batch flush\n   * 3. Flushes any remaining logs\n   * 4. Waits for any in-progress compression to complete\n   * 5. Closes the write stream\n   * 6. Removes the filename from the registry\n   */\n  [Symbol.dispose](): void {\n    if (this.stream || this.batchEnabled) {\n      this.isDisposing = true;\n\n      if (this.batchTimer) {\n        clearTimeout(this.batchTimer);\n        this.batchTimer = null;\n      }\n\n      // Flush any remaining logs\n      if (this.batchEnabled) {\n        this.flush();\n      }\n\n      const checkAndEnd = () => {\n        if (!this.isCompressing) {\n          if (this.stream) {\n            this.stream.end();\n          }\n          // Remove the filename from registry when disposed\n          LogFileRotationTransport.activeFilenames.delete(this.filename);\n        } else {\n          setTimeout(checkAndEnd, 100);\n        }\n      };\n      checkAndEnd();\n    }\n  }\n}\n"]}