add: a logger utils

This commit is contained in:
2026-04-24 14:02:16 +02:00
parent 38f9f087d1
commit 8c84663472
4 changed files with 146 additions and 5 deletions
+6 -1
View File
@@ -1,3 +1,5 @@
import { logger } from "@/utils/logger";
export class AudioManager {
private static _instance: AudioManager | null = null;
private readonly _audioPools = new Map<string, HTMLAudioElement[]>();
@@ -31,7 +33,10 @@ export class AudioManager {
return;
}
console.error(`Failed to play sound: ${path}`, error);
logger.error("AudioManager", "Failed to play sound", {
path,
error,
});
});
}
+13 -4
View File
@@ -9,6 +9,10 @@ export class InteractionManager {
private _focused: InteractableHandle | null = null;
private _holding = false;
private _holdingHandle: InteractableHandle | null = null;
private _snapshot: InteractionSnapshot = {
focused: null,
holding: false,
};
private readonly _listeners = new Set<() => void>();
static getInstance(): InteractionManager {
@@ -22,10 +26,7 @@ export class InteractionManager {
private constructor() {}
getState(): InteractionSnapshot {
return {
focused: this._focused,
holding: this._holding,
};
return this._snapshot;
}
setFocused(handle: InteractableHandle | null): void {
@@ -67,11 +68,19 @@ export class InteractionManager {
this._focused = null;
this._holding = false;
this._holdingHandle = null;
this._snapshot = {
focused: null,
holding: false,
};
this._listeners.clear();
InteractionManager._instance = null;
}
private _emit(): void {
this._snapshot = {
focused: this._focused,
holding: this._holding,
};
this._listeners.forEach((cb) => cb());
}
}
+15
View File
@@ -0,0 +1,15 @@
export type LogLevel = "debug" | "info" | "warn" | "error";
export type LogContext = Record<string, unknown>;
export interface LogEntry {
timestamp: string;
level: LogLevel;
scope: string;
message: string;
context?: LogContext;
}
export interface LoggerConfig {
minLevel: LogLevel;
}
+112
View File
@@ -0,0 +1,112 @@
import type {
LogContext,
LogEntry,
LogLevel,
LoggerConfig,
} from "@/types/logger";
const LEVEL_PRIORITY: Record<LogLevel, number> = {
debug: 10,
info: 20,
warn: 30,
error: 40,
};
const LEVEL_LABELS: Record<LogLevel, string> = {
debug: "DEBUG",
info: "INFO",
warn: "WARN",
error: "ERROR",
};
const LEVEL_STYLES: Record<LogLevel, string> = {
debug: "color: #94a3b8; font-weight: 600;",
info: "color: #60a5fa; font-weight: 600;",
warn: "color: #f59e0b; font-weight: 600;",
error: "color: #f87171; font-weight: 600;",
};
const SCOPE_STYLE = "color: #e5e7eb; font-weight: 600;";
const MESSAGE_STYLE = "color: inherit;";
class Logger {
private readonly config: LoggerConfig;
constructor(config: LoggerConfig) {
this.config = config;
}
debug(scope: string, message: string, context?: LogContext): void {
this.log("debug", scope, message, context);
}
info(scope: string, message: string, context?: LogContext): void {
this.log("info", scope, message, context);
}
warn(scope: string, message: string, context?: LogContext): void {
this.log("warn", scope, message, context);
}
error(scope: string, message: string, context?: LogContext): void {
this.log("error", scope, message, context);
}
private log(
level: LogLevel,
scope: string,
message: string,
context?: LogContext,
): void {
if (!this.shouldLog(level)) return;
const entry: LogEntry = {
timestamp: new Date().toISOString(),
level,
scope,
message,
...(context ? { context } : {}),
};
const formattedMessage = `%c[${LEVEL_LABELS[level]}]%c [${scope}]%c ${message}`;
const args = [
formattedMessage,
LEVEL_STYLES[level],
SCOPE_STYLE,
MESSAGE_STYLE,
entry,
] as const;
switch (level) {
case "debug":
console.debug(...args);
return;
case "info":
console.info(...args);
return;
case "warn":
console.warn(...args);
return;
case "error":
console.error(...args);
}
}
private shouldLog(level: LogLevel): boolean {
return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[this.config.minLevel];
}
}
function resolveMinLevel(): LogLevel {
if (typeof window === "undefined") {
return "info";
}
const debugEnabled = new URLSearchParams(window.location.search).has("debug");
return debugEnabled ? "debug" : "info";
}
export const logger = new Logger({
minLevel: resolveMinLevel(),
});