src / utils / Logger.ts
src / utils / Logger.ts
import { Config } from "../config/Config";
export type UnbracketedLogCategory =
| "Config"
| "Registry"
| "SearchEngine"
| "SearchPipeline"
| "ImageSearch"
| "Provider"
| "KeyManager"
| "WebpageReader"
| "InspectImages"
| "HTTPClient"
| "HTMLExtractor"
| "Title"
| "TimeDependencyDetector"
| "ImageContextDetector"
| "VisionContextDetector"
| "SiteAdapter"
| "RedditAdapter";
export type LegacyBracketedLogCategory =
| "[Config]"
| "[Registry]"
| "[SearchEngine]"
| "[SearchPipeline]"
| "[ImageSearch]"
| "[Provider]"
| "[KeyManager]"
| "[WebpageReader]"
| "[InspectImages]"
| "[HTTPClient]"
| "[HTMLExtractor]"
| "[Title]"
| "[TimeDependencyDetector]"
| "[ImageContextDetector]"
| "[VisionContextDetector]"
| "[SiteAdapter]"
| "[RedditAdapter]";
export type LogCategory = UnbracketedLogCategory | LegacyBracketedLogCategory;
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
/**
* Structured, category-based Logger for Browse.
* Supports configurable log levels and category filtering.
*/
export class Logger {
private static readonly COLOR_RESET = "\x1b[0m";
private static readonly LEVEL_COLORS: Record<LogLevel, string> = {
[LogLevel.DEBUG]: "\x1b[90m", // Gray
[LogLevel.INFO]: "", // Default terminal color
[LogLevel.WARN]: "\x1b[33m", // Yellow
[LogLevel.ERROR]: "\x1b[31m", // Red
};
private static readonly LEVEL_LABELS: Record<LogLevel, string> = {
[LogLevel.DEBUG]: "[DEBUG]",
[LogLevel.INFO]: "[INFO] ",
[LogLevel.WARN]: "[WARN] ",
[LogLevel.ERROR]: "[ERROR]",
};
public static info(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.INFO, category, message, ...extra);
}
public static debug(category: LogCategory, message: string, ...extra: unknown[]): void {
if (Config.isDebugEnabled()) {
this.log(LogLevel.DEBUG, category, message, ...extra);
}
}
public static warn(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.WARN, category, message, ...extra);
}
public static error(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.ERROR, category, message, ...extra);
}
private static log(
level: LogLevel,
category: LogCategory,
message: string,
...extra: unknown[]
): void {
const color = Logger.LEVEL_COLORS[level] || "";
const label = Logger.LEVEL_LABELS[level] || "[INFO] ";
const coloredLabel = color ? `${color}${label}${Logger.COLOR_RESET}` : label;
const categoryFormatted = category.startsWith("[") ? category : `[${category}]`;
const prefix = `${coloredLabel} ${categoryFormatted}`;
if (extra.length > 0) {
console.log(prefix, message, ...extra);
} else {
console.log(prefix, message);
}
}
}
import { Config } from "../config/Config";
export type UnbracketedLogCategory =
| "Config"
| "Registry"
| "SearchEngine"
| "SearchPipeline"
| "ImageSearch"
| "Provider"
| "KeyManager"
| "WebpageReader"
| "InspectImages"
| "HTTPClient"
| "HTMLExtractor"
| "Title"
| "TimeDependencyDetector"
| "ImageContextDetector"
| "VisionContextDetector"
| "SiteAdapter"
| "RedditAdapter";
export type LegacyBracketedLogCategory =
| "[Config]"
| "[Registry]"
| "[SearchEngine]"
| "[SearchPipeline]"
| "[ImageSearch]"
| "[Provider]"
| "[KeyManager]"
| "[WebpageReader]"
| "[InspectImages]"
| "[HTTPClient]"
| "[HTMLExtractor]"
| "[Title]"
| "[TimeDependencyDetector]"
| "[ImageContextDetector]"
| "[VisionContextDetector]"
| "[SiteAdapter]"
| "[RedditAdapter]";
export type LogCategory = UnbracketedLogCategory | LegacyBracketedLogCategory;
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
/**
* Structured, category-based Logger for Browse.
* Supports configurable log levels and category filtering.
*/
export class Logger {
private static readonly COLOR_RESET = "\x1b[0m";
private static readonly LEVEL_COLORS: Record<LogLevel, string> = {
[LogLevel.DEBUG]: "\x1b[90m", // Gray
[LogLevel.INFO]: "", // Default terminal color
[LogLevel.WARN]: "\x1b[33m", // Yellow
[LogLevel.ERROR]: "\x1b[31m", // Red
};
private static readonly LEVEL_LABELS: Record<LogLevel, string> = {
[LogLevel.DEBUG]: "[DEBUG]",
[LogLevel.INFO]: "[INFO] ",
[LogLevel.WARN]: "[WARN] ",
[LogLevel.ERROR]: "[ERROR]",
};
public static info(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.INFO, category, message, ...extra);
}
public static debug(category: LogCategory, message: string, ...extra: unknown[]): void {
if (Config.isDebugEnabled()) {
this.log(LogLevel.DEBUG, category, message, ...extra);
}
}
public static warn(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.WARN, category, message, ...extra);
}
public static error(category: LogCategory, message: string, ...extra: unknown[]): void {
this.log(LogLevel.ERROR, category, message, ...extra);
}
private static log(
level: LogLevel,
category: LogCategory,
message: string,
...extra: unknown[]
): void {
const color = Logger.LEVEL_COLORS[level] || "";
const label = Logger.LEVEL_LABELS[level] || "[INFO] ";
const coloredLabel = color ? `${color}${label}${Logger.COLOR_RESET}` : label;
const categoryFormatted = category.startsWith("[") ? category : `[${category}]`;
const prefix = `${coloredLabel} ${categoryFormatted}`;
if (extra.length > 0) {
console.log(prefix, message, ...extra);
} else {
console.log(prefix, message);
}
}
}