refactor(backend): split log files into separate file
This commit is contained in:
14
lib/log/constants.ts
Normal file
14
lib/log/constants.ts
Normal 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
52
lib/log/fs.ts
Normal 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
52
lib/log/index.ts
Normal 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
32
lib/log/types.ts
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user