logger->ts

This commit is contained in:
Alex Holliday
2026-01-20 22:56:14 +00:00
parent c6ac48b4ff
commit cc9850c975
2 changed files with 57 additions and 56 deletions
@@ -1,6 +1,7 @@
import { logger } from "../../utils/logger.js";
import type { NextFunction, Request, Response } from "express";
import { logger } from "@/utils/logger.js";
const handleErrors = (error, req, res, next) => {
const handleErrors = (error: any, req: Request, res: Response, next: NextFunction) => {
const status = error.status || 500;
const message = error.message || "Server error";
const service = error.service || "unknownService";
@@ -10,7 +11,7 @@ const handleErrors = (error, req, res, next) => {
method: error.method,
stack: error.stack,
});
res.error({
res.status(status).json({
status,
msg: message,
});
@@ -1,46 +1,76 @@
import { createLogger, format, transports } from "winston";
import { createLogger, format, transports, Logger as WinstonLogger } from "winston";
import type { Logform } from "winston";
import dotenv from "dotenv";
dotenv.config();
const SERVICE_NAME = "Logger";
interface LogConfig {
message: string;
service?: string;
method?: string;
details?: Record<string, unknown>;
stack?: string;
}
interface LogEntry extends LogConfig {
level: string;
timestamp: string;
}
interface EnvSettings {
logLevel?: string;
}
class Logger {
static SERVICE_NAME = SERVICE_NAME;
constructor({ envSettings }) {
private logger: WinstonLogger;
private envSettings: EnvSettings;
private logCache: LogEntry[];
private maxCacheSize: number;
constructor({ envSettings }: { envSettings: EnvSettings }) {
this.envSettings = envSettings;
this.logCache = [];
this.maxCacheSize = 1000;
const consoleFormat = format.printf(({ level, message, service, method, details, timestamp, stack }) => {
if (message instanceof Object) {
message = JSON.stringify(message, null, 2);
const consoleFormat = format.printf((info: Logform.TransformableInfo) => {
const { level, service, method, details, timestamp, stack } = info;
let message = info.message as string;
let formattedMessage: string = message;
let formattedDetails: string | undefined;
if (typeof message === "object" && message !== null) {
formattedMessage = JSON.stringify(message, null, 2);
}
if (details instanceof Object) {
details = JSON.stringify(details, null, 2);
if (typeof details === "object" && details !== null) {
formattedDetails = JSON.stringify(details, null, 2);
}
let msg = `${timestamp} ${level}:`;
service && (msg += ` [${service}]`);
method && (msg += `(${method})`);
message && (msg += ` ${message}`);
details && (msg += ` (details: ${details})`);
formattedMessage && (msg += ` ${formattedMessage}`);
formattedDetails && (msg += ` (details: ${formattedDetails})`);
if (typeof stack !== "undefined") {
if (typeof stack === "string") {
const stackTrace = stack
?.split("\n")
.split("\n")
.slice(1) // Remove first line (error message)
.map((line) => {
.map((line: string) => {
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
if (match) {
return {
function: match[1],
file: match[2],
line: parseInt(match[3]),
column: parseInt(match[4]),
line: parseInt(match[3] ?? "0", 10),
column: parseInt(match[4] ?? "0", 10),
};
}
return line.trim();
});
stack && (msg += ` (stack: ${JSON.stringify(stackTrace, null, 2)})`);
msg += ` (stack: ${JSON.stringify(stackTrace, null, 2)})`;
}
return msg;
@@ -67,62 +97,31 @@ class Logger {
return Logger.SERVICE_NAME;
}
/**
* Logs an informational message.
* @param {Object} config - The configuration object.
* @param {string} config.message - The message to log.
* @param {string} config.service - The service name.
* @param {string} config.method - The method name.
* @param {Object} config.details - Additional details.
*/
info(config) {
info(config: LogConfig) {
const logEntry = this.buildLogEntry("info", config);
this.cacheLog(logEntry);
this.logger.info(logEntry);
}
/**
* Logs a warning message.
* @param {Object} config - The configuration object.
* @param {string} config.message - The message to log.
* @param {string} config.service - The service name.
* @param {string} config.method - The method name.
* @param {Object} config.details - Additional details.
*/
warn(config) {
warn(config: LogConfig) {
const logEntry = this.buildLogEntry("warn", config);
this.cacheLog(logEntry);
this.logger.warn(logEntry);
}
/**
* Logs an error message.
* @param {Object} config - The configuration object.
* @param {string} config.message - The message to log.
* @param {string} config.service - The service name.
* @param {string} config.method - The method name.
* @param {Object} config.details - Additional details.
*/
error(config) {
error(config: LogConfig) {
const logEntry = this.buildLogEntry("error", config);
this.cacheLog(logEntry);
this.logger.error(logEntry);
}
/**
* Logs a debug message.
* @param {Object} config - The configuration object.
* @param {string} config.message - The message to log.
* @param {string} config.service - The service name.
* @param {string} config.method - The method name.
* @param {Object} config.details - Additional details.
*/
debug(config) {
debug(config: LogConfig) {
const logEntry = this.buildLogEntry("debug", config);
this.cacheLog(logEntry);
this.logger.debug(logEntry);
}
cacheLog(entry) {
cacheLog(entry: LogEntry) {
this.logCache.push(entry);
if (this.logCache.length > this.maxCacheSize) {
this.logCache.shift();
@@ -133,7 +132,7 @@ class Logger {
return this.logCache;
}
buildLogEntry(level, config) {
buildLogEntry(level: string, config: LogConfig): LogEntry {
return {
level,
message: config.message,
@@ -151,3 +150,4 @@ export default Logger;
// Legacy logger
const logger = new Logger({ envSettings: { logLevel: "debug" } });
export { logger };
export type { LogConfig, LogEntry };