feat: rich log viewers for all remaining log types
- Syslog-style table (postfix, dovecot, sogo, netfilter, acme): Time | Priority badge (colour-coded debug→info→notice→warn→error→crit) | Process | Message — columns hidden when unused by that log type - API access log: Time | Method badge (GET=green, POST=blue, PUT=orange, DELETE=red) | Endpoint | Remote IP | Data - Autodiscover: Time | User | Service badge (ActiveSync, CalDAV, CardDAV, IMAP, SMTP) | User Agent - Watchdog: Time | Service | Health badge (Healthy/Degraded/Critical based on lvl) | Processes (now/total) | Change (+/-/±0 coloured) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -952,6 +952,168 @@
|
|||||||
$('#wc-log-wrap').html(html);
|
$('#wc-log-wrap').html(html);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ── Syslog-style renderer (postfix, dovecot, sogo, netfilter, acme) ──
|
||||||
|
|
||||||
|
const priorityBadge = (priority) => {
|
||||||
|
const p = (priority || 'info').toLowerCase();
|
||||||
|
const styles = {
|
||||||
|
debug: 'background:#f0f0f0;color:#888',
|
||||||
|
info: 'background:#e9ecef;color:#495057',
|
||||||
|
notice: 'background:#cce5ff;color:#004085',
|
||||||
|
warn: 'background:#fff3cd;color:#856404',
|
||||||
|
warning: 'background:#fff3cd;color:#856404',
|
||||||
|
err: 'background:#f8d7da;color:#721c24',
|
||||||
|
error: 'background:#f8d7da;color:#721c24',
|
||||||
|
crit: 'background:#721c24;color:#fff',
|
||||||
|
critical: 'background:#721c24;color:#fff',
|
||||||
|
alert: 'background:#721c24;color:#fff',
|
||||||
|
emerg: 'background:#1a1a1a;color:#fff',
|
||||||
|
};
|
||||||
|
const style = styles[p] || 'background:#e9ecef;color:#495057';
|
||||||
|
const label = p.charAt(0).toUpperCase() + p.slice(1);
|
||||||
|
return `<span class="woocow-badge" style="${style}">${label}</span>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSyslogTable = (entries, label) => {
|
||||||
|
const hasProgram = entries.some(e => e.program);
|
||||||
|
const hasPriority = entries.some(e => e.priority);
|
||||||
|
let html = `<div class="woocow-log-toolbar">
|
||||||
|
<strong>${esc(label)}</strong>
|
||||||
|
<span style="color:#666;font-size:12px">${entries.length} entries</span>
|
||||||
|
</div>
|
||||||
|
<table class="wp-list-table widefat fixed striped woocow-table">
|
||||||
|
<thead><tr>
|
||||||
|
<th style="width:140px">Time</th>
|
||||||
|
${hasPriority ? '<th style="width:80px">Priority</th>' : ''}
|
||||||
|
${hasProgram ? '<th style="width:150px">Process</th>' : ''}
|
||||||
|
<th>Message</th>
|
||||||
|
</tr></thead><tbody>`;
|
||||||
|
entries.forEach(e => {
|
||||||
|
const dt = e.time ? new Date(parseInt(e.time) * 1000).toLocaleString() : '—';
|
||||||
|
html += `<tr>
|
||||||
|
<td style="font-size:11px;white-space:nowrap">${esc(dt)}</td>
|
||||||
|
${hasPriority ? `<td>${priorityBadge(e.priority)}</td>` : ''}
|
||||||
|
${hasProgram ? `<td><code style="font-size:11px">${esc(e.program || '—')}</code></td>` : ''}
|
||||||
|
<td style="font-size:12px;word-break:break-word">${esc(e.message || '—')}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#wc-log-wrap').html(html);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── API access log renderer ───────────────────────────────────────────
|
||||||
|
|
||||||
|
const renderApiLog = (entries) => {
|
||||||
|
const methodBadge = (method) => {
|
||||||
|
const colors = { GET:'#27ae60', POST:'#2271b1', PUT:'#e67e22', DELETE:'#c0392b', PATCH:'#8e44ad' };
|
||||||
|
const bg = colors[(method || '').toUpperCase()] || '#555';
|
||||||
|
return `<span style="display:inline-block;padding:1px 7px;border-radius:3px;background:${bg};color:#fff;font-size:11px;font-weight:700;font-family:monospace">${esc(method || '?')}</span>`;
|
||||||
|
};
|
||||||
|
let html = `<div class="woocow-log-toolbar">
|
||||||
|
<strong>API Access Log</strong>
|
||||||
|
<span style="color:#666;font-size:12px">${entries.length} requests</span>
|
||||||
|
</div>
|
||||||
|
<table class="wp-list-table widefat fixed striped woocow-table">
|
||||||
|
<thead><tr>
|
||||||
|
<th style="width:140px">Time</th>
|
||||||
|
<th style="width:72px">Method</th>
|
||||||
|
<th>Endpoint</th>
|
||||||
|
<th style="width:110px">Remote IP</th>
|
||||||
|
<th style="width:160px">Data</th>
|
||||||
|
</tr></thead><tbody>`;
|
||||||
|
entries.forEach(e => {
|
||||||
|
const dt = e.time ? new Date(e.time * 1000).toLocaleString() : '—';
|
||||||
|
html += `<tr>
|
||||||
|
<td style="font-size:11px;white-space:nowrap">${esc(dt)}</td>
|
||||||
|
<td>${methodBadge(e.method)}</td>
|
||||||
|
<td><code style="font-size:11px">${esc(e.uri || '—')}</code></td>
|
||||||
|
<td><code style="font-size:11px">${esc(e.remote || '—')}</code></td>
|
||||||
|
<td style="font-size:11px;color:#888;word-break:break-all">${esc(e.data || '—')}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#wc-log-wrap').html(html);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Autodiscover log renderer ─────────────────────────────────────────
|
||||||
|
|
||||||
|
const renderAutodiscoverLog = (entries) => {
|
||||||
|
const svcBadge = (svc) => {
|
||||||
|
const map = {
|
||||||
|
activesync: ['woocow-badge-blue', 'ActiveSync'],
|
||||||
|
caldav: ['woocow-badge-green', 'CalDAV'],
|
||||||
|
carddav: ['woocow-badge-green', 'CardDAV'],
|
||||||
|
imap: ['woocow-badge-grey', 'IMAP'],
|
||||||
|
smtp: ['woocow-badge-grey', 'SMTP'],
|
||||||
|
};
|
||||||
|
const [cls, label] = map[(svc || '').toLowerCase()] || ['woocow-badge-grey', esc(svc || '—')];
|
||||||
|
return `<span class="woocow-badge ${cls}">${label}</span>`;
|
||||||
|
};
|
||||||
|
let html = `<div class="woocow-log-toolbar">
|
||||||
|
<strong>Autodiscover Log</strong>
|
||||||
|
<span style="color:#666;font-size:12px">${entries.length} requests</span>
|
||||||
|
</div>
|
||||||
|
<table class="wp-list-table widefat fixed striped woocow-table">
|
||||||
|
<thead><tr>
|
||||||
|
<th style="width:140px">Time</th>
|
||||||
|
<th>User</th>
|
||||||
|
<th style="width:120px">Service</th>
|
||||||
|
<th>User Agent</th>
|
||||||
|
</tr></thead><tbody>`;
|
||||||
|
entries.forEach(e => {
|
||||||
|
const dt = e.time ? new Date(e.time * 1000).toLocaleString() : '—';
|
||||||
|
html += `<tr>
|
||||||
|
<td style="font-size:11px;white-space:nowrap">${esc(dt)}</td>
|
||||||
|
<td style="font-size:12px">${esc(e.user || '—')}</td>
|
||||||
|
<td>${svcBadge(e.service)}</td>
|
||||||
|
<td style="font-size:11px;color:#666">${esc(e.ua || '—')}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#wc-log-wrap').html(html);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Watchdog log renderer ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
const renderWatchdogLog = (entries) => {
|
||||||
|
const healthBadge = (lvl) => {
|
||||||
|
const n = parseInt(lvl) || 0;
|
||||||
|
if (n >= 100) return '<span class="woocow-badge woocow-badge-green">Healthy</span>';
|
||||||
|
if (n >= 50) return '<span class="woocow-badge woocow-badge-orange">Degraded</span>';
|
||||||
|
return '<span class="woocow-badge woocow-badge-red">Critical</span>';
|
||||||
|
};
|
||||||
|
let html = `<div class="woocow-log-toolbar">
|
||||||
|
<strong>Watchdog Log</strong>
|
||||||
|
<span style="color:#666;font-size:12px">${entries.length} entries</span>
|
||||||
|
</div>
|
||||||
|
<table class="wp-list-table widefat fixed striped woocow-table">
|
||||||
|
<thead><tr>
|
||||||
|
<th style="width:140px">Time</th>
|
||||||
|
<th style="width:140px">Service</th>
|
||||||
|
<th style="width:90px">Status</th>
|
||||||
|
<th style="width:100px">Processes</th>
|
||||||
|
<th style="width:70px">Change</th>
|
||||||
|
</tr></thead><tbody>`;
|
||||||
|
entries.forEach(e => {
|
||||||
|
const dt = e.time ? new Date(parseInt(e.time) * 1000).toLocaleString() : '—';
|
||||||
|
const diff = parseInt(e.hpdiff) || 0;
|
||||||
|
const diffHtml = diff > 0
|
||||||
|
? `<span style="color:#27ae60;font-weight:700">+${diff}</span>`
|
||||||
|
: diff < 0
|
||||||
|
? `<span style="color:#c0392b;font-weight:700">${diff}</span>`
|
||||||
|
: `<span style="color:#bbb">±0</span>`;
|
||||||
|
html += `<tr>
|
||||||
|
<td style="font-size:11px;white-space:nowrap">${esc(dt)}</td>
|
||||||
|
<td><strong>${esc(e.service || '—')}</strong></td>
|
||||||
|
<td>${healthBadge(e.lvl)}</td>
|
||||||
|
<td style="font-family:monospace">${esc(e.hpnow || '0')}/${esc(e.hptotal || '0')}</td>
|
||||||
|
<td>${diffHtml}</td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#wc-log-wrap').html(html);
|
||||||
|
};
|
||||||
|
|
||||||
// ── Log load ──────────────────────────────────────────────────────────
|
// ── Log load ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
$('#wc-log-load').on('click', () => {
|
$('#wc-log-load').on('click', () => {
|
||||||
@@ -969,24 +1131,14 @@
|
|||||||
$('#wc-log-wrap').html('<p>No log entries.</p>');
|
$('#wc-log-wrap').html('<p>No log entries.</p>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const typeLabel = $('#wc-log-type option:selected').text();
|
||||||
if (type === 'rspamd-history') { renderRspamdLog(entries); return; }
|
if (type === 'rspamd-history') { renderRspamdLog(entries); return; }
|
||||||
if (type === 'ratelimited') { renderRatelimitLog(entries); return; }
|
if (type === 'ratelimited') { renderRatelimitLog(entries); return; }
|
||||||
|
if (type === 'api') { renderApiLog(entries); return; }
|
||||||
// Plain text log
|
if (type === 'autodiscover') { renderAutodiscoverLog(entries); return; }
|
||||||
const typeLabel = $('#wc-log-type option:selected').text();
|
if (type === 'watchdog') { renderWatchdogLog(entries); return; }
|
||||||
const text = entries.map(e => {
|
// postfix, dovecot, sogo, netfilter, acme → syslog table
|
||||||
if (typeof e === 'string') return e;
|
renderSyslogTable(entries, typeLabel + ' Log');
|
||||||
if (e.time && e.message) return `[${e.time}] ${e.message}`;
|
|
||||||
return JSON.stringify(e);
|
|
||||||
}).join('\n');
|
|
||||||
$('#wc-log-wrap').html(`
|
|
||||||
<div class="woocow-log-toolbar">
|
|
||||||
<strong>${esc(typeLabel)} log</strong>
|
|
||||||
<span style="color:#666;font-size:12px">${entries.length} entries</span>
|
|
||||||
</div>
|
|
||||||
<pre class="woocow-log-pre">${esc(text)}</pre>
|
|
||||||
`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user