Code cleanup, add color and pretty dates to LogManagers

This commit is contained in:
Jesse Wierzbinski 2024-04-13 22:12:41 -10:00
parent 327a716b12
commit bc051ed043
No known key found for this signature in database
3 changed files with 103 additions and 33 deletions

View file

@ -2,6 +2,12 @@ import { config } from "config-manager";
import { drizzle } from "drizzle-orm/node-postgres"; import { drizzle } from "drizzle-orm/node-postgres";
import { Client } from "pg"; import { Client } from "pg";
import * as schema from "./schema"; import * as schema from "./schema";
import {
LogLevel,
type LogManager,
type MultiLogManager,
} from "~packages/log-manager";
import { migrate } from "drizzle-orm/postgres-js/migrator";
export const client = new Client({ export const client = new Client({
host: config.database.host, host: config.database.host,
@ -11,4 +17,38 @@ export const client = new Client({
database: config.database.database, database: config.database.database,
}); });
export const setupDatabase = async (logger: LogManager | MultiLogManager) => {
try {
await client.connect();
} catch (e) {
await logger.logError(LogLevel.CRITICAL, "Database", e as Error);
await logger.log(
LogLevel.CRITICAL,
"Database",
"Failed to connect to database. Please check your configuration.",
);
process.exit(1);
}
// Migrate the database
await logger.log(LogLevel.INFO, "Database", "Migrating database...");
try {
await migrate(db, {
migrationsFolder: "./drizzle",
});
} catch (e) {
await logger.logError(LogLevel.CRITICAL, "Database", e as Error);
await logger.log(
LogLevel.CRITICAL,
"Database",
"Failed to migrate database. Please check your configuration.",
);
process.exit(1);
}
await logger.log(LogLevel.INFO, "Database", "Database migrated");
};
export const db = drizzle(client, { schema }); export const db = drizzle(client, { schema });

View file

@ -1,46 +1,31 @@
import { exists, mkdir, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
import { connectMeili } from "@meilisearch"; import { connectMeili } from "@meilisearch";
import { moduleIsEntry } from "@module";
import { config } from "config-manager"; import { config } from "config-manager";
import { count, sql } from "drizzle-orm"; import { count } from "drizzle-orm";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import { LogLevel, LogManager, MultiLogManager } from "log-manager"; import { LogLevel, LogManager, MultiLogManager } from "log-manager";
import { db, client as pgClient } from "~drizzle/db"; import { db, setupDatabase } from "~drizzle/db";
import { status } from "~drizzle/schema"; import { status } from "~drizzle/schema";
import { createServer } from "~server"; import { createServer } from "~server";
await pgClient.connect();
await migrate(db, {
migrationsFolder: "./drizzle",
});
const timeAtStart = performance.now(); const timeAtStart = performance.now();
// Create requests file if it doesnt exist const requests_log = Bun.file(config.logging.storage.requests);
if ( const isEntry = import.meta.path === Bun.main;
!(await exists(
`${process.cwd()}/${dirname(config.logging.storage.requests)}`, const noColors = process.env.NO_COLORS === "true";
)) const noFancyDates = process.env.NO_FANCY_DATES === "true";
) {
await mkdir(`${process.cwd()}/${dirname(config.logging.storage.requests)}`);
await writeFile(`${process.cwd()}/${config.logging.storage.requests}`, "");
}
const requests_log = Bun.file(
`${process.cwd()}/${config.logging.storage.requests}`,
);
const isEntry = moduleIsEntry(import.meta.url);
// If imported as a module, redirect logs to /dev/null to not pollute console (e.g. in tests) // If imported as a module, redirect logs to /dev/null to not pollute console (e.g. in tests)
const logger = new LogManager(isEntry ? requests_log : Bun.file("/dev/null")); const logger = new LogManager(isEntry ? requests_log : Bun.file("/dev/null"));
const consoleLogger = new LogManager( const consoleLogger = new LogManager(
isEntry ? Bun.stdout : Bun.file("/dev/null"), isEntry ? Bun.stdout : Bun.file("/dev/null"),
!noColors,
!noFancyDates,
); );
const dualLogger = new MultiLogManager([logger, consoleLogger]); const dualLogger = new MultiLogManager([logger, consoleLogger]);
await dualLogger.log(LogLevel.INFO, "Lysand", "Starting Lysand..."); await dualLogger.log(LogLevel.INFO, "Lysand", "Starting Lysand...");
// NODE_ENV seems to be broken and output `development` even when set to production, so use the flag instead await setupDatabase(dualLogger);
const isProd =
process.env.NODE_ENV === "production" || process.argv.includes("--prod");
if (config.meilisearch.enabled) { if (config.meilisearch.enabled) {
await connectMeili(dualLogger); await connectMeili(dualLogger);
@ -63,7 +48,7 @@ try {
process.exit(1); process.exit(1);
} }
const server = createServer(config, dualLogger, isProd); const server = createServer(config, dualLogger, true);
await dualLogger.log( await dualLogger.log(
LogLevel.INFO, LogLevel.INFO,

View file

@ -1,6 +1,7 @@
import { appendFile, exists, mkdir } from "node:fs/promises"; import { appendFile, exists, mkdir } from "node:fs/promises";
import { dirname } from "node:path"; import { dirname } from "node:path";
import type { BunFile } from "bun"; import type { BunFile } from "bun";
import chalk from "chalk";
export enum LogLevel { export enum LogLevel {
DEBUG = "debug", DEBUG = "debug",
@ -15,12 +16,44 @@ export enum LogLevel {
* @param output BunFile of output (can be a normal file or something like Bun.stdout) * @param output BunFile of output (can be a normal file or something like Bun.stdout)
*/ */
export class LogManager { export class LogManager {
constructor(private output: BunFile) { constructor(
private output: BunFile,
private enableColors = false,
private prettyDates = false,
) {
void this.write( void this.write(
`--- INIT LogManager at ${new Date().toISOString()} ---`, `--- INIT LogManager at ${new Date().toISOString()} ---`,
); );
} }
getLevelColor(level: LogLevel) {
switch (level) {
case LogLevel.DEBUG:
return chalk.blue;
case LogLevel.INFO:
return chalk.green;
case LogLevel.WARNING:
return chalk.yellow;
case LogLevel.ERROR:
return chalk.red;
case LogLevel.CRITICAL:
return chalk.bgRed;
}
}
getFormattedDate(date: Date = new Date()) {
return this.prettyDates
? date.toLocaleString(undefined, {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
})
: date.toISOString();
}
/** /**
* Logs a message to the output * Logs a message to the output
* @param level Importance of the log * @param level Importance of the log
@ -34,12 +67,24 @@ export class LogManager {
message: string, message: string,
showTimestamp = true, showTimestamp = true,
) { ) {
if (this.enableColors) {
await this.write( await this.write(
`${ `${
showTimestamp ? `${new Date().toISOString()} ` : "" showTimestamp
? `${chalk.gray(this.getFormattedDate())} `
: ""
}[${this.getLevelColor(level)(
level.toUpperCase(),
)}] ${chalk.bold(entity)}: ${message}`,
);
} else {
await this.write(
`${
showTimestamp ? `${this.getFormattedDate()} ` : ""
}[${level.toUpperCase()}] ${entity}: ${message}`, }[${level.toUpperCase()}] ${entity}: ${message}`,
); );
} }
}
private async write(text: string) { private async write(text: string) {
Bun.stdout.name; Bun.stdout.name;