{% extends "base.html" %} {% block title %}Debug Panel - Norda Biznes Partner{% endblock %} {% block extra_css %} {% endblock %} {% block content %}

Debug Panel

0 INFO
0 WARNING
0 ERROR
0 Total
Oczekiwanie na logi... Wykonaj jakąś akcję na stronie.
{% endblock %} {% block extra_js %} let confirmResolve = null; function showConfirm(message, options = {}) { return new Promise(resolve => { confirmResolve = resolve; document.getElementById('confirmModalIcon').textContent = options.icon || '❓'; document.getElementById('confirmModalTitle').textContent = options.title || 'Potwierdzenie'; document.getElementById('confirmModalMessage').innerHTML = message; document.getElementById('confirmModalOk').textContent = options.okText || 'OK'; document.getElementById('confirmModalOk').className = 'btn ' + (options.okClass || 'btn-primary'); document.getElementById('confirmModal').classList.add('active'); }); } function closeConfirm(result) { document.getElementById('confirmModal').classList.remove('active'); if (confirmResolve) { confirmResolve(result); confirmResolve = null; } } document.getElementById('confirmModalOk').addEventListener('click', () => closeConfirm(true)); document.getElementById('confirmModalCancel').addEventListener('click', () => closeConfirm(false)); document.getElementById('confirmModal').addEventListener('click', e => { if (e.target.id === 'confirmModal') closeConfirm(false); }); const logContainer = document.getElementById('logContainer'); const emptyMessage = document.getElementById('emptyMessage'); const statusIndicator = document.getElementById('statusIndicator'); const levelFilter = document.getElementById('levelFilter'); const autoScrollCheckbox = document.getElementById('autoScroll'); let stats = { DEBUG: 0, INFO: 0, WARNING: 0, ERROR: 0 }; let allLogs = []; let eventSource = null; // Format timestamp function formatTime(isoString) { const date = new Date(isoString); return date.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); } // Add log entry to UI function addLogEntry(log) { allLogs.push(log); stats[log.level] = (stats[log.level] || 0) + 1; updateStats(); // Check filter const filter = levelFilter.value; if (filter && log.level !== filter) return; emptyMessage.style.display = 'none'; const entry = document.createElement('div'); entry.className = `log-entry ${log.level}`; entry.innerHTML = ` ${formatTime(log.timestamp)} ${log.level} ${log.logger} ${escapeHtml(log.message)} ${log.module}:${log.lineno} `; logContainer.appendChild(entry); if (autoScrollCheckbox.checked) { logContainer.scrollTop = logContainer.scrollHeight; } } // Escape HTML function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Update stats function updateStats() { document.getElementById('infoCount').textContent = stats.INFO || 0; document.getElementById('warningCount').textContent = stats.WARNING || 0; document.getElementById('errorCount').textContent = stats.ERROR || 0; document.getElementById('totalCount').textContent = allLogs.length; } // Poll for new logs (SSE doesn't work well with session auth) let lastLogTimestamp = ''; let pollInterval = null; function startPolling() { statusIndicator.classList.add('connected'); pollInterval = setInterval(async () => { try { const url = lastLogTimestamp ? `/api/admin/logs?limit=50&since=${encodeURIComponent(lastLogTimestamp)}` : '/api/admin/logs?limit=50'; const response = await fetch(url, { credentials: 'include' }); const data = await response.json(); if (data.success && data.logs.length > 0) { data.logs.forEach(log => { addLogEntry(log); lastLogTimestamp = log.timestamp; }); } } catch (error) { console.error('Polling error:', error); statusIndicator.classList.remove('connected'); } }, 1000); // Poll every second } function stopPolling() { if (pollInterval) { clearInterval(pollInterval); pollInterval = null; } statusIndicator.classList.remove('connected'); } // Load initial logs async function loadInitialLogs() { try { const response = await fetch('/api/admin/logs?limit=200', { credentials: 'include' }); const data = await response.json(); if (data.success && data.logs.length > 0) { data.logs.forEach(log => addLogEntry(log)); } } catch (error) { console.error('Failed to load logs:', error); } } // Filter logs levelFilter.addEventListener('change', function() { // Clear container logContainer.innerHTML = ''; const filter = this.value; const filtered = filter ? allLogs.filter(l => l.level === filter) : allLogs; if (filtered.length === 0) { logContainer.innerHTML = '
Brak logów dla wybranego filtru
'; } else { filtered.forEach(log => { const entry = document.createElement('div'); entry.className = `log-entry ${log.level}`; entry.innerHTML = ` ${formatTime(log.timestamp)} ${log.level} ${log.logger} ${escapeHtml(log.message)} ${log.module}:${log.lineno} `; logContainer.appendChild(entry); }); } }); // Clear logs async function clearLogs() { const confirmed = await showConfirm('Czy na pewno chcesz wyczyścić wszystkie logi?', { icon: '🗑️', title: 'Czyszczenie logów', okText: 'Wyczyść', okClass: 'btn-danger' }); if (!confirmed) return; try { const response = await fetch('/api/admin/logs/clear', { method: 'POST', credentials: 'include', headers: { 'X-CSRFToken': '{{ csrf_token() }}' } }); if (response.ok) { allLogs = []; stats = { DEBUG: 0, INFO: 0, WARNING: 0, ERROR: 0 }; updateStats(); logContainer.innerHTML = '
Logi wyczyszczone
'; } } catch (error) { console.error('Failed to clear logs:', error); } } // Test logs async function testLogs() { try { await fetch('/api/admin/test-log', { method: 'POST', credentials: 'include', headers: { 'X-CSRFToken': '{{ csrf_token() }}' } }); } catch (error) { console.error('Failed to generate test logs:', error); } } // Initialize loadInitialLogs(); startPolling(); // Cleanup on page unload window.addEventListener('beforeunload', stopPolling); {% endblock %}