add: a logger utils
This commit is contained in:
@@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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(),
|
||||
});
|
||||
Reference in New Issue
Block a user