// Logs Page Module class LogsPage { constructor() { this.logs = []; this.init(); } async init() { await this.loadLogs(); this.setupEventListeners(); } async loadLogs() { const tableBody = document.querySelector('#logs-table tbody'); if (tableBody) tableBody.innerHTML = 'Loading logs...'; try { const data = await window.api.get('/system/logs'); this.logs = data; this.renderLogs(); } catch (error) { console.error('Error loading logs:', error); window.authManager.showToast('Failed to load system logs', 'error'); } } renderLogs() { const tableBody = document.querySelector('#logs-table tbody'); if (!tableBody) return; if (this.logs.length === 0) { tableBody.innerHTML = 'No logs found'; return; } tableBody.innerHTML = this.logs.map(log => { const statusClass = log.status === 'success' ? 'success' : 'danger'; const timestamp = luxon.DateTime.fromISO(log.timestamp).toFormat('yyyy-MM-dd HH:mm:ss'); let tokenDetails = `${log.tokens} total tokens`; if (log.status === 'success') { const parts = []; parts.push(`${log.prompt_tokens} in`); let completionStr = `${log.completion_tokens} out`; if (log.reasoning_tokens > 0) { completionStr += ` (${log.reasoning_tokens} reasoning)`; } parts.push(completionStr); if (log.cache_read_tokens > 0) { parts.push(`${log.cache_read_tokens} cache-hit`); } tokenDetails = parts.join(', '); } return ` ${timestamp} ${log.status.toUpperCase()}
${log.client_id} ${log.provider}
${log.model} ${tokenDetails} ${log.duration}ms ${log.error ? `
${log.error}
` : ''}
`; }).join(''); } setupEventListeners() { const refreshBtn = document.getElementById('refresh-btn'); if (refreshBtn) { // Already handled by dashboard.js but we can add more specific logic if needed } const logFilter = document.getElementById('log-filter'); if (logFilter) { logFilter.onchange = () => this.filterLogs(); } const logSearch = document.getElementById('log-search'); if (logSearch) { logSearch.oninput = (e) => this.searchLogs(e.target.value); } } filterLogs() { const filter = document.getElementById('log-filter').value; if (filter === 'all') { this.renderLogs(); return; } const filtered = this.logs.filter(log => log.status === (filter === 'error' ? 'error' : 'success')); this.renderFilteredLogs(filtered); } searchLogs(query) { if (!query) { this.renderLogs(); return; } const q = query.toLowerCase(); const filtered = this.logs.filter(log => log.client_id.toLowerCase().includes(q) || log.model.toLowerCase().includes(q) || log.provider.toLowerCase().includes(q) || (log.error && log.error.toLowerCase().includes(q)) ); this.renderFilteredLogs(filtered); } renderFilteredLogs(filteredLogs) { // reuse same rendering logic or similar const originalLogs = this.logs; this.logs = filteredLogs; this.renderLogs(); this.logs = originalLogs; } } window.initLogs = async () => { window.logsPage = new LogsPage(); };