// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { LogLevels } from "./levels.ts";
import { BaseHandler } from "./base_handler.ts";
const PAGE_SIZE = 4096;
/**
 * This handler will output to a file using an optional mode (default is `a`,
 * e.g. append). The file will grow indefinitely. It uses a buffer for writing
 * to file. Logs can be manually flushed with `fileHandler.flush()`. Log
 * messages with a log level greater than error are immediately flushed. Logs
 * are also flushed on process completion.
 *
 * Behavior of the log modes is as follows:
 *
 * - `'a'` - Default mode. Appends new log messages to the end of an existing log
 *   file, or create a new log file if none exists.
 * - `'w'` - Upon creation of the handler, any existing log file will be removed
 *   and a new one created.
 * - `'x'` - This will create a new log file and throw an error if one already
 *   exists.
 *
 * This handler requires `--allow-write` permission on the log file.
 */ export class FileHandler extends BaseHandler {
  _file;
  _buf = new Uint8Array(PAGE_SIZE);
  _pointer = 0;
  _filename;
  _mode;
  _openOptions;
  _encoder = new TextEncoder();
  #unloadCallback = (()=>{
    this.destroy();
  }).bind(this);
  constructor(levelName, options){
    super(levelName, options);
    this._filename = options.filename;
    // default to append mode, write only
    this._mode = options.mode ? options.mode : "a";
    this._openOptions = {
      createNew: this._mode === "x",
      create: this._mode !== "x",
      append: this._mode === "a",
      truncate: this._mode !== "a",
      write: true
    };
  }
  setup() {
    this._file = Deno.openSync(this._filename, this._openOptions);
    this.#resetBuffer();
    addEventListener("unload", this.#unloadCallback);
  }
  handle(logRecord) {
    super.handle(logRecord);
    // Immediately flush if log level is higher than ERROR
    if (logRecord.level > LogLevels.ERROR) {
      this.flush();
    }
  }
  log(msg) {
    const bytes = this._encoder.encode(msg + "\n");
    if (bytes.byteLength > this._buf.byteLength - this._pointer) {
      this.flush();
    }
    this._buf.set(bytes, this._pointer);
    this._pointer += bytes.byteLength;
  }
  flush() {
    if (this._pointer > 0 && this._file) {
      let written = 0;
      while(written < this._pointer){
        written += this._file.writeSync(this._buf.subarray(written, this._pointer));
      }
      this.#resetBuffer();
    }
  }
  #resetBuffer() {
    this._pointer = 0;
  }
  destroy() {
    this.flush();
    this._file?.close();
    this._file = undefined;
    removeEventListener("unload", this.#unloadCallback);
  }
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 6756 characters]