Skip to content

Commit

Permalink
refactor(log): replace protected properties with Symbols (#5724)
Browse files Browse the repository at this point in the history
  • Loading branch information
timreichen authored Aug 20, 2024
1 parent 06da501 commit 2d6ae7d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 40 deletions.
8 changes: 8 additions & 0 deletions log/_file_handler_symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
export const fileSymbol = Symbol("file");
export const bufSymbol = Symbol("buf");
export const pointerSymbol = Symbol("pointer");
export const filenameSymbol = Symbol("filename");
export const modeSymbol = Symbol("mode");
export const openOptionsSymbol = Symbol("openOptions");
export const encoderSymbol = Symbol("encoder");
70 changes: 41 additions & 29 deletions log/file_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import { type LevelName, LogLevels } from "./levels.ts";
import type { LogRecord } from "./logger.ts";
import { BaseHandler, type BaseHandlerOptions } from "./base_handler.ts";
import { writeAllSync } from "@std/io/write-all";
import {
bufSymbol,
encoderSymbol,
filenameSymbol,
fileSymbol,
modeSymbol,
openOptionsSymbol,
pointerSymbol,
} from "./_file_handler_symbols.ts";

export type LogMode = "a" | "w" | "x";

Expand Down Expand Up @@ -36,34 +45,37 @@ export interface FileHandlerOptions extends BaseHandlerOptions {
* This handler requires `--allow-write` permission on the log file.
*/
export class FileHandler extends BaseHandler {
protected _file: Deno.FsFile | undefined;
protected _buf: Uint8Array;
protected _pointer = 0;
protected _filename: string;
protected _mode: LogMode;
protected _openOptions: Deno.OpenOptions;
protected _encoder: TextEncoder = new TextEncoder();
[fileSymbol]: Deno.FsFile | undefined;
[bufSymbol]: Uint8Array;
[pointerSymbol] = 0;
[filenameSymbol]: string;
[modeSymbol]: LogMode;
[openOptionsSymbol]: Deno.OpenOptions;
[encoderSymbol]: TextEncoder = new TextEncoder();
#unloadCallback = (() => {
this.destroy();
}).bind(this);

constructor(levelName: LevelName, options: FileHandlerOptions) {
super(levelName, options);
this._filename = options.filename;
this[filenameSymbol] = 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",
this[modeSymbol] = options.mode ? options.mode : "a";
this[openOptionsSymbol] = {
createNew: this[modeSymbol] === "x",
create: this[modeSymbol] !== "x",
append: this[modeSymbol] === "a",
truncate: this[modeSymbol] !== "a",
write: true,
};
this._buf = new Uint8Array(options.bufferSize ?? 4096);
this[bufSymbol] = new Uint8Array(options.bufferSize ?? 4096);
}

override setup() {
this._file = Deno.openSync(this._filename, this._openOptions);
this[fileSymbol] = Deno.openSync(
this[filenameSymbol],
this[openOptionsSymbol],
);
this.#resetBuffer();

addEventListener("unload", this.#unloadCallback);
Expand All @@ -79,38 +91,38 @@ export class FileHandler extends BaseHandler {
}

override log(msg: string) {
const bytes = this._encoder.encode(msg + "\n");
if (bytes.byteLength > this._buf.byteLength - this._pointer) {
const bytes = this[encoderSymbol].encode(msg + "\n");
if (bytes.byteLength > this[bufSymbol].byteLength - this[pointerSymbol]) {
this.flush();
}
if (bytes.byteLength > this._buf.byteLength) {
writeAllSync(this._file!, bytes);
if (bytes.byteLength > this[bufSymbol].byteLength) {
writeAllSync(this[fileSymbol]!, bytes);
} else {
this._buf.set(bytes, this._pointer);
this._pointer += bytes.byteLength;
this[bufSymbol].set(bytes, this[pointerSymbol]);
this[pointerSymbol] += bytes.byteLength;
}
}

flush() {
if (this._pointer > 0 && this._file) {
if (this[pointerSymbol] > 0 && this[fileSymbol]) {
let written = 0;
while (written < this._pointer) {
written += this._file.writeSync(
this._buf.subarray(written, this._pointer),
while (written < this[pointerSymbol]) {
written += this[fileSymbol].writeSync(
this[bufSymbol].subarray(written, this[pointerSymbol]),
);
}
this.#resetBuffer();
}
}

#resetBuffer() {
this._pointer = 0;
this[pointerSymbol] = 0;
}

override destroy() {
this.flush();
this._file?.close();
this._file = undefined;
this[fileSymbol]?.close();
this[fileSymbol] = undefined;
removeEventListener("unload", this.#unloadCallback);
}
}
33 changes: 22 additions & 11 deletions log/rotating_file_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
import type { LevelName } from "./levels.ts";
import { existsSync } from "@std/fs/exists";
import { FileHandler, type FileHandlerOptions } from "./file_handler.ts";
import {
encoderSymbol,
filenameSymbol,
fileSymbol,
modeSymbol,
openOptionsSymbol,
} from "./_file_handler_symbols.ts";

interface RotatingFileHandlerOptions extends FileHandlerOptions {
maxBytes: number;
Expand Down Expand Up @@ -68,35 +75,36 @@ export class RotatingFileHandler extends FileHandler {
}
super.setup();

if (this._mode === "w") {
if (this[modeSymbol] === "w") {
// Remove old backups too as it doesn't make sense to start with a clean
// log file, but old backups
for (let i = 1; i <= this.#maxBackupCount; i++) {
try {
Deno.removeSync(this._filename + "." + i);
Deno.removeSync(this[filenameSymbol] + "." + i);
} catch (error) {
if (!(error instanceof Deno.errors.NotFound)) {
throw error;
}
}
}
} else if (this._mode === "x") {
} else if (this[modeSymbol] === "x") {
// Throw if any backups also exist
for (let i = 1; i <= this.#maxBackupCount; i++) {
if (existsSync(this._filename + "." + i)) {
if (existsSync(this[filenameSymbol] + "." + i)) {
this.destroy();
throw new Deno.errors.AlreadyExists(
"Backup log file " + this._filename + "." + i + " already exists",
"Backup log file " + this[filenameSymbol] + "." + i +
" already exists",
);
}
}
} else {
this.#currentFileSize = (Deno.statSync(this._filename)).size;
this.#currentFileSize = (Deno.statSync(this[filenameSymbol])).size;
}
}

override log(msg: string) {
const msgByteLength = this._encoder.encode(msg).byteLength + 1;
const msgByteLength = this[encoderSymbol].encode(msg).byteLength + 1;

if (this.#currentFileSize + msgByteLength > this.#maxBytes) {
this.rotateLogFiles();
Expand All @@ -110,17 +118,20 @@ export class RotatingFileHandler extends FileHandler {

rotateLogFiles() {
this.flush();
this._file!.close();
this[fileSymbol]!.close();

for (let i = this.#maxBackupCount - 1; i >= 0; i--) {
const source = this._filename + (i === 0 ? "" : "." + i);
const dest = this._filename + "." + (i + 1);
const source = this[filenameSymbol] + (i === 0 ? "" : "." + i);
const dest = this[filenameSymbol] + "." + (i + 1);

if (existsSync(source)) {
Deno.renameSync(source, dest);
}
}

this._file = Deno.openSync(this._filename, this._openOptions);
this[fileSymbol] = Deno.openSync(
this[filenameSymbol],
this[openOptionsSymbol],
);
}
}

0 comments on commit 2d6ae7d

Please sign in to comment.