let currentConfig = null; let componentsData = null; // Load configuration on page load window.addEventListener('DOMContentLoaded', () => { loadConfiguration(); loadComponents(); }); async function loadConfiguration() { try { const response = await fetch('/api/log/config'); const data = await response.json(); if (data.success) { currentConfig = data.config; // Load timestamp format setting const timestampFormat = data.config.formatting?.timestamp_format || 'datetime'; const timestampSelect = document.getElementById('timestampFormat'); if (timestampSelect) { timestampSelect.value = timestampFormat; } } else { showNotification('Failed to load configuration', 'error'); } } catch (error) { showNotification('Error loading configuration: ' + error.message, 'error'); } } async function loadComponents() { try { const response = await fetch('/api/log/components'); const data = await response.json(); if (data.success) { componentsData = data; renderComponentsTable(); populatePreviewSelect(); } else { showNotification('Failed to load components', 'error'); } } catch (error) { showNotification('Error loading components: ' + error.message, 'error'); } } function renderComponentsTable() { const tbody = document.getElementById('componentsTable'); tbody.innerHTML = ''; for (const [name, description] of Object.entries(componentsData.components)) { const stats = componentsData.stats[name] || {}; const enabled = stats.enabled !== undefined ? stats.enabled : true; const enabledLevels = stats.enabled_levels || ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']; const allLevels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']; if (name === 'api.requests') { allLevels.push('API'); } const levelCheckboxes = allLevels.map(level => { const emoji = {'DEBUG': '🔍', 'INFO': 'â„šī¸', 'WARNING': 'âš ī¸', 'ERROR': '❌', 'CRITICAL': 'đŸ”Ĩ', 'API': '🌐'}[level]; const checked = enabledLevels.includes(level) ? 'checked' : ''; return `
`; }).join(''); const row = document.createElement('tr'); row.innerHTML = `
${name}
${description}
${levelCheckboxes}
${enabled ? 'Active' : 'Inactive'} `; tbody.appendChild(row); if (name === 'api.requests') { document.getElementById('enabled_' + name).addEventListener('change', (e) => { document.getElementById('apiFilters').style.display = e.target.checked ? 'block' : 'none'; }); if (enabled) { document.getElementById('apiFilters').style.display = 'block'; loadApiFilters(); } } } // Update global level checkboxes based on current state updateGlobalLevelCheckboxes(); } function updateGlobalLevelCheckboxes() { const allLevels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'API']; for (const level of allLevels) { let allComponentsHaveLevel = true; // Check if ALL components have this level enabled for (const [name, description] of Object.entries(componentsData.components)) { const stats = componentsData.stats[name] || {}; const enabledLevels = stats.enabled_levels || []; // Skip API level for non-api.requests components if (level === 'API' && name !== 'api.requests') { continue; } if (!enabledLevels.includes(level)) { allComponentsHaveLevel = false; break; } } const checkbox = document.getElementById('global_' + level); if (checkbox) { checkbox.checked = allComponentsHaveLevel; } } } function populatePreviewSelect() { const select = document.getElementById('previewComponent'); select.innerHTML = ''; for (const name of Object.keys(componentsData.components)) { const option = document.createElement('option'); option.value = name; option.textContent = name; select.appendChild(option); } loadLogPreview(); } async function updateComponentEnabled(component) { const enabled = document.getElementById('enabled_' + component).checked; try { const response = await fetch('/api/log/config', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ component: component, enabled: enabled }) }); const data = await response.json(); if (data.success) { showNotification(`${enabled ? 'Enabled' : 'Disabled'} ${component}`, 'success'); const row = document.getElementById('enabled_' + component).closest('tr'); const statusCell = row.querySelector('td:last-child'); statusCell.innerHTML = ` ${enabled ? 'Active' : 'Inactive'} `; } else { showNotification('Failed to update ' + component + ': ' + data.error, 'error'); } } catch (error) { showNotification('Error updating component: ' + error.message, 'error'); } } async function updateGlobalLevel(level, enabled) { try { const response = await fetch(`/api/log/global-level?level=${level}&enabled=${enabled}`, { method: 'POST', headers: {'Content-Type': 'application/json'} }); const data = await response.json(); if (data.success) { const action = enabled ? 'enabled' : 'disabled'; showNotification(`${level} ${action} globally across all components`, 'success'); // Reload components to reflect changes await loadComponents(); } else { showNotification('Failed to update global level: ' + data.error, 'error'); } } catch (error) { showNotification('Error updating global level: ' + error.message, 'error'); } } async function updateTimestampFormat(format) { try { const response = await fetch(`/api/log/timestamp-format?format_type=${format}`, { method: 'POST', headers: {'Content-Type': 'application/json'} }); const data = await response.json(); if (data.success) { showNotification(`Timestamp format updated: ${format}`, 'success'); // Reload all loggers to apply the change await fetch('/api/log/reload', { method: 'POST' }); } else { showNotification('Failed to update timestamp format: ' + data.error, 'error'); } } catch (error) { showNotification('Error updating timestamp format: ' + error.message, 'error'); } } async function updateComponentLevels(component) { const allLevels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']; if (component === 'api.requests') { allLevels.push('API'); } const enabledLevels = allLevels.filter(level => { const checkbox = document.getElementById(`level_${component}_${level}`); return checkbox && checkbox.checked; }); try { const response = await fetch('/api/log/config', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ component: component, enabled_levels: enabledLevels }) }); const data = await response.json(); if (data.success) { showNotification(`Updated levels for ${component}: ${enabledLevels.join(', ')}`, 'success'); // Update global level checkboxes to reflect current state updateGlobalLevelCheckboxes(); } else { showNotification('Failed to update ' + component + ': ' + data.error, 'error'); } } catch (error) { showNotification('Error updating component: ' + error.message, 'error'); } } async function loadApiFilters() { if (!currentConfig || !currentConfig.components['api.requests']) return; const filters = currentConfig.components['api.requests'].filters || {}; document.getElementById('excludePaths').value = (filters.exclude_paths || []).join(', '); document.getElementById('excludeStatus').value = (filters.exclude_status || []).join(', '); document.getElementById('includeSlowRequests').checked = filters.include_slow_requests !== false; document.getElementById('slowThreshold').value = filters.slow_threshold_ms || 1000; } async function saveApiFilters() { const excludePaths = document.getElementById('excludePaths').value .split(',') .map(s => s.trim()) .filter(s => s.length > 0); const excludeStatus = document.getElementById('excludeStatus').value .split(',') .map(s => parseInt(s.trim())) .filter(n => !isNaN(n)); const includeSlowRequests = document.getElementById('includeSlowRequests').checked; const slowThreshold = parseInt(document.getElementById('slowThreshold').value); try { const response = await fetch('/api/log/filters', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ exclude_paths: excludePaths, exclude_status: excludeStatus, include_slow_requests: includeSlowRequests, slow_threshold_ms: slowThreshold }) }); const data = await response.json(); if (data.success) { showNotification('API filters saved', 'success'); } else { showNotification('Failed to save filters: ' + data.error, 'error'); } } catch (error) { showNotification('Error saving filters: ' + error.message, 'error'); } } async function saveAllSettings() { try { const response = await fetch('/api/log/reload', { method: 'POST' }); const data = await response.json(); if (data.success) { showNotification('All settings saved and reloaded', 'success'); await loadConfiguration(); await loadComponents(); } else { showNotification('Failed to reload settings: ' + data.error, 'error'); } } catch (error) { showNotification('Error saving settings: ' + error.message, 'error'); } } async function resetToDefaults() { if (!confirm('Are you sure you want to reset all logging settings to defaults?')) { return; } try { const response = await fetch('/api/log/reset', { method: 'POST' }); const data = await response.json(); if (data.success) { showNotification('Settings reset to defaults', 'success'); await loadConfiguration(); await loadComponents(); } else { showNotification('Failed to reset settings: ' + data.error, 'error'); } } catch (error) { showNotification('Error resetting settings: ' + error.message, 'error'); } } async function loadLogPreview() { const component = document.getElementById('previewComponent').value; const preview = document.getElementById('logPreview'); preview.innerHTML = '
Loading logs...
'; try { const response = await fetch(`/api/log/files/${component}?lines=50`); const data = await response.json(); if (data.success) { if (data.lines.length === 0) { preview.innerHTML = '
No logs yet for this component
'; } else { preview.innerHTML = data.lines.map(line => `
${escapeHtml(line)}
` ).join(''); preview.scrollTop = preview.scrollHeight; } } else { preview.innerHTML = `
Error: ${data.error}
`; } } catch (error) { preview.innerHTML = `
Error loading logs: ${error.message}
`; } } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function showNotification(message, type) { const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 3000); } // Auto-refresh log preview every 5 seconds setInterval(() => { if (document.getElementById('previewComponent').value) { loadLogPreview(); } }, 5000);