export default class Logger {
constructor(config = {}) {
this.levels = { debug: 0, info: 1, warn: 2, error: 3 };
this.currentLevel = config.level || 'info';
this.maxLogs = config.maxLogs || 100;
this.enableRemote = config.enableRemote || false;
this.remoteEndpoint = config.remoteEndpoint || '/api/logs';
this._setupGlobalHandlers();
}
log(level, message, data = null) {
const levelIndex = this.levels[level];
const currentIndex = this.levels[this.currentLevel];
if (levelIndex < currentIndex) return;
const timestamp = new Date().toISOString();
const entry = {
timestamp,
level,
message,
data,
url: window.location.href,
userAgent: navigator.userAgent
};
this._console(level, message, data);
this._persistLog(entry);
if (this.enableRemote && level === 'error') {
this._sendRemote(entry);
}
}
debug(message, data) { this.log('debug', message, data); }
info(message, data) { this.log('info', message, data); }
warn(message, data) { this.log('warn', message, data); }
error(message, data) { this.log('error', message, data); }
_console(level, message, data) {
const logFn = console[level] || console.log;
const timestamp = new Date().toISOString();
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
logFn(`${prefix} ${message}`, data || '');
}
_persistLog(entry) {
if (typeof localStorage === 'undefined') return;
try {
const logs = JSON.parse(localStorage.getItem('app_logs') || '[]');
logs.push(entry);
if (logs.length > this.maxLogs) {
logs.splice(0, logs.length - this.maxLogs);
}
localStorage.setItem('app_logs', JSON.stringify(logs));
} catch (err) {
console.error('Failed to persist log:', err);
}
}
_sendRemote(entry) {
fetch(this.remoteEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(entry)
}).catch(err => console.error('Remote logging failed:', err));
}
_setupGlobalHandlers() {
window.addEventListener('error', (event) => {
this.error(`JavaScript Error: ${event.message}`, {
file: event.filename,
line: event.lineno,
column: event.colno,
stack: event.error?.stack
});
});
window.addEventListener('unhandledrejection', (event) => {
this.error(`Unhandled Promise Rejection: ${event.reason}`, {
stack: event.reason?.stack
});
});
}
exportLogs() {
if (typeof localStorage === 'undefined') return [];
return JSON.parse(localStorage.getItem('app_logs') || '[]');
}
clearLogs() {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem('app_logs');
}
}
}