refactor(backend): split log files into separate file

This commit is contained in:
2025-01-19 16:43:00 +01:00
parent e9cc56d7ee
commit f106460502
24 changed files with 155 additions and 113 deletions

14
lib/log/constants.ts Normal file
View File

@@ -0,0 +1,14 @@
import * as env from "@lib/env.ts";
import { ensureDir } from "https://deno.land/std@0.224.0/fs/mod.ts";
import { join } from "node:path";
import { getLogLevel, LOG_LEVEL } from "@lib/log/types.ts";
export const LOG_DIR = join(env.DATA_DIR, "logs");
// Ensure the log directory exists
await ensureDir(LOG_DIR);
export let logLevel = getLogLevel(env.LOG_LEVEL);
export function setLogLevel(level: LOG_LEVEL) {
logLevel = level;
}

52
lib/log/fs.ts Normal file
View File

@@ -0,0 +1,52 @@
import { join } from "node:path";
import { LOG_DIR } from "@lib/log/constants.ts";
import { Log } from "@lib/log/types.ts";
function getLogFileName() {
const d = new Date();
const year = d.getFullYear();
const month = (d.getMonth() + 1).toString().padStart(2, "0"); // Ensure two digits
const day = d.getDate().toString().padStart(2, "0"); // Ensure two digits
return `${year}-${month}-${day}.log`;
}
export function writeLogEntry(entry: Log) {
const logEntry = JSON.stringify(entry);
const logFilePath = join(LOG_DIR, getLogFileName());
// Append the log entry to the file (creating it if it doesn't exist)
Deno.writeTextFile(
logFilePath,
new Date().toISOString() + " | " + logEntry + "\n",
{ append: true },
);
}
export async function getLogs() {
const logFilePath = join(LOG_DIR, getLogFileName());
try {
// Read the log file content
const logFileContent = await Deno.readTextFile(logFilePath);
// Split by lines and parse logs
const logs: Log[] = logFileContent
.split("\n")
.filter((line) => line.trim() !== "")
.map((line) => {
const [date, ...rest] = line.split(" | ");
const parsed = JSON.parse(rest.join(" | ")) as Log;
return {
...parsed,
date: new Date(date),
} as Log;
});
console.log(logs);
// Return the logs sorted by date
return logs.sort((a, b) => a.date.getTime() - b.date.getTime());
} catch (_error) {
// If file does not exist, return an empty array
return [];
}
}

52
lib/log/index.ts Normal file
View File

@@ -0,0 +1,52 @@
import { StreamResponse } from "@lib/helpers.ts";
import { writeLogEntry } from "@lib/log/fs.ts";
import { LOG_LEVEL, Logger } from "@lib/log/types.ts";
import { logLevel } from "@lib/log/constants.ts";
let longestScope = 0;
type LoggerOptions = {
enabled?: boolean;
};
const createLogFunction = (scope: string, level: LOG_LEVEL) => {
return (...data: unknown[]) => {
writeLogEntry({ level, scope, args: data, date: new Date() });
if (level < logLevel) return;
const logFunc = {
[LOG_LEVEL.DEBUG]: console.debug,
[LOG_LEVEL.INFO]: console.info,
[LOG_LEVEL.WARN]: console.warn,
[LOG_LEVEL.ERROR]: console.error,
}[level];
logFunc(`[${scope.padEnd(longestScope, " ")}]`, ...data);
};
};
export function createLogger(scope: string, _options?: LoggerOptions): Logger {
longestScope = Math.max(scope.length, longestScope);
return {
debug: createLogFunction(scope, LOG_LEVEL.DEBUG),
info: createLogFunction(scope, LOG_LEVEL.INFO),
error: createLogFunction(scope, LOG_LEVEL.ERROR),
warn: createLogFunction(scope, LOG_LEVEL.WARN),
};
}
export function loggerFromStream(stream: StreamResponse) {
return {
debug: (...data: unknown[]) =>
stream.enqueue(`${data.length > 1 ? data.join(" ") : data[0]}`),
info: (...data: unknown[]) =>
stream.enqueue(`${data.length > 1 ? data.join(" ") : data[0]}`),
error: (...data: unknown[]) =>
stream.enqueue(`[ERROR]: ${data.length > 1 ? data.join(" ") : data[0]}`),
warn: (...data: unknown[]) =>
stream.enqueue(`[WARN]: ${data.length > 1 ? data.join(" ") : data[0]}`),
};
}
export type { Log } from "@lib/log/types.ts";
export { getLogs } from "@lib/log/fs.ts";

32
lib/log/types.ts Normal file
View File

@@ -0,0 +1,32 @@
export enum LOG_LEVEL {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
export function getLogLevel(level: string): LOG_LEVEL {
switch (level) {
case "debug":
return LOG_LEVEL.DEBUG;
case "warn":
return LOG_LEVEL.WARN;
case "error":
return LOG_LEVEL.ERROR;
default:
return LOG_LEVEL.INFO;
}
}
export type Log = {
scope: string;
level: number;
date: Date;
args: unknown[];
};
export interface Logger {
debug: (...data: unknown[]) => void;
info: (...data: unknown[]) => void;
error: (...data: unknown[]) => void;
warn: (...data: unknown[]) => void;
}