Supra_App/src/lib/core/utils/logger.ts
pakintada@gmail.com f0619c5a10 feat: migrate recipe editor
- using eventbus in recipe editor
- migrate to logging instead of console log
- fix case swap not saved, value not update after change, topping slot bug

Signed-off-by: pakintada@gmail.com <Pakin>
2026-06-19 17:27:28 +07:00

91 lines
2.3 KiB
TypeScript

/**
* Lightweight logger that suppresses output in production.
*
* In development (npm run dev): logs are shown with a prefix tag.
* In production (npm run build): all console output is suppressed
* so logs are never exposed to the browser inspector.
*
* Usage:
* import { logger } from '$lib/core/utils/logger';
* logger.info('hello', someVar);
* logger.error('failed', err);
*/
type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
const LOG_LEVEL_RANK: Record<LogLevel, number> = {
trace: -1,
debug: 0,
info: 1,
warn: 2,
error: 3
};
const ENV_LOG_LEVEL: LogLevel =
(import.meta.env.PUBLIC_APP_LOG_LEVEL as LogLevel) || 'info';
const IS_DEV = import.meta.env.DEV;
function shouldLog(level: LogLevel): boolean {
return IS_DEV && LOG_LEVEL_RANK[level] >= LOG_LEVEL_RANK[ENV_LOG_LEVEL];
}
function formatArgs(level: LogLevel, args: any[]): any[] {
return [`[${level.toUpperCase()}]`, ...args];
}
/**
* Extract caller location (file:line) from a stack trace.
* Stack frame format: " at method (file:///path/file.ts:10:20)"
* The 3rd frame (index 2) is the caller of the method that created the Error.
*/
function getCallerLocation(): string {
try {
const stack = new Error().stack?.split('\n');
if (!stack || stack.length < 3) return 'unknown';
// stack[0] = "Error", stack[1] = " at getCallerLocation (...)",
// stack[2] = " at Logger.trace (...)" — skip both
const caller = stack[2]?.trim();
// Extract path from common formats:
// "at method (file:///path/file.ts:10:20)" or "at file:///path/file.ts:10:20"
const match = caller.match(/(?:\(|at\s+)([^(]+?\.\w+):(\d+)/);
if (match) return `${match[1]}:${match[2]}`;
return caller || 'unknown';
} catch {
return 'unknown';
}
}
class Logger {
trace(...args: any[]) {
if (shouldLog('trace')) {
const location = getCallerLocation();
console.debug(`[TRACE:${location}]`, ...args);
}
}
debug(...args: any[]) {
if (shouldLog('debug')) {
console.debug(...formatArgs('debug', args));
}
}
info(...args: any[]) {
if (shouldLog('info')) {
console.info(...formatArgs('info', args));
}
}
warn(...args: any[]) {
if (shouldLog('warn')) {
console.warn(...formatArgs('warn', args));
}
}
error(...args: any[]) {
if (shouldLog('error')) {
console.error(...formatArgs('error', args));
}
}
}
export const logger = new Logger();