initial commit
This commit is contained in:
84
hameter/web/templates/logs.html
Normal file
84
hameter/web/templates/logs.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Logs - HAMeter{% endblock %}
|
||||
{% block page_title %}Logs{% endblock %}
|
||||
|
||||
{% block top_actions %}
|
||||
<div class="log-controls">
|
||||
<select id="log-level-filter" onchange="filterLogs()">
|
||||
<option value="">All Levels</option>
|
||||
<option value="DEBUG">DEBUG</option>
|
||||
<option value="INFO">INFO</option>
|
||||
<option value="WARNING">WARNING</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
</select>
|
||||
<input type="text" id="log-search" placeholder="Filter..." oninput="filterLogs()">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="log-autoscroll" checked> Auto-scroll
|
||||
</label>
|
||||
<button class="btn btn-sm btn-secondary" onclick="clearLogs()">Clear</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="log-viewer" id="log-viewer"></div>
|
||||
|
||||
<script>
|
||||
const logViewer = document.getElementById('log-viewer');
|
||||
let allLogs = [];
|
||||
|
||||
// Load initial logs
|
||||
fetch('/api/logs?count=500')
|
||||
.then(r => r.json())
|
||||
.then(logs => {
|
||||
allLogs = logs;
|
||||
renderLogs();
|
||||
});
|
||||
|
||||
function addLogEntry(entry) {
|
||||
allLogs.push(entry);
|
||||
if (allLogs.length > 2000) allLogs = allLogs.slice(-1000);
|
||||
renderLogs();
|
||||
}
|
||||
|
||||
function renderLogs() {
|
||||
const level = document.getElementById('log-level-filter').value;
|
||||
const search = document.getElementById('log-search').value.toLowerCase();
|
||||
|
||||
const filtered = allLogs.filter(log => {
|
||||
if (level && log.level !== level) return false;
|
||||
if (search && !log.message.toLowerCase().includes(search) && !log.name.toLowerCase().includes(search)) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
logViewer.innerHTML = filtered.map(log => {
|
||||
const cls = 'log-' + (log.level || 'INFO').toLowerCase();
|
||||
return '<div class="log-line ' + cls + '">' +
|
||||
'<span class="log-ts">' + (log.timestamp || '') + '</span> ' +
|
||||
'<span class="log-level">[' + (log.level || '?') + ']</span> ' +
|
||||
'<span class="log-name">' + (log.name || '') + ':</span> ' +
|
||||
'<span class="log-msg">' + escapeHtml(log.message || '') + '</span>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
|
||||
if (document.getElementById('log-autoscroll').checked) {
|
||||
logViewer.scrollTop = logViewer.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function filterLogs() { renderLogs(); }
|
||||
function clearLogs() { allLogs = []; renderLogs(); }
|
||||
|
||||
function escapeHtml(s) {
|
||||
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
// SSE log handler
|
||||
if (typeof window._onLogUpdate === 'undefined') {
|
||||
window._onLogUpdate = function(logs) {
|
||||
if (Array.isArray(logs)) {
|
||||
logs.forEach(addLogEntry);
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user