133 lines
6.2 KiB
Plaintext
133 lines
6.2 KiB
Plaintext
<%- include("partials/layout-top", { title }) %>
|
|
<% const filters = logFilters || { range: '86400000', level: 'all', limit: '50' }; %>
|
|
<section class="card">
|
|
<div class="section-header">
|
|
<div>
|
|
<h1>Logs</h1>
|
|
<p class="command-subtitle">Core system logs with severity, timestamps, and details.</p>
|
|
</div>
|
|
<div class="log-controls">
|
|
<label>
|
|
<span>Search</span>
|
|
<input
|
|
class="table-search"
|
|
type="search"
|
|
placeholder="Search logs"
|
|
aria-label="Search logs"
|
|
data-log-search
|
|
/>
|
|
</label>
|
|
<label>
|
|
<span>Severity</span>
|
|
<select class="table-search" data-log-level aria-label="Filter log severity">
|
|
<option value="all" <%= filters.level === 'all' ? 'selected' : '' %>>All severities</option>
|
|
<option value="error" <%= filters.level === 'error' ? 'selected' : '' %>>Error</option>
|
|
<option value="warn" <%= filters.level === 'warn' ? 'selected' : '' %>>Warning</option>
|
|
<option value="info" <%= filters.level === 'info' ? 'selected' : '' %>>Info</option>
|
|
<option value="debug" <%= filters.level === 'debug' ? 'selected' : '' %>>Debug</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
<span>Range</span>
|
|
<select class="table-search" data-log-range aria-label="Filter by time range">
|
|
<option value="all" <%= filters.range === 'all' ? 'selected' : '' %>>All time</option>
|
|
<option value="<%= 5 * 60 * 1000 %>" <%= filters.range === `${5 * 60 * 1000}` ? 'selected' : '' %>>Last 5 minutes</option>
|
|
<option value="<%= 60 * 60 * 1000 %>" <%= filters.range === `${60 * 60 * 1000}` ? 'selected' : '' %>>Last hour</option>
|
|
<option value="<%= 24 * 60 * 60 * 1000 %>" <%= filters.range === `${24 * 60 * 60 * 1000}` ? 'selected' : '' %>>Last 24 hours</option>
|
|
<option value="<%= 7 * 24 * 60 * 60 * 1000 %>" <%= filters.range === `${7 * 24 * 60 * 60 * 1000}` ? 'selected' : '' %>>Last week</option>
|
|
<option value="<%= 30 * 24 * 60 * 60 * 1000 %>" <%= filters.range === `${30 * 24 * 60 * 60 * 1000}` ? 'selected' : '' %>>Last month</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
<span>Entries</span>
|
|
<select class="table-search" data-log-limit aria-label="Limit log entries">
|
|
<option value="50" <%= filters.limit === '50' ? 'selected' : '' %>>50 most recent</option>
|
|
<option value="100" <%= filters.limit === '100' ? 'selected' : '' %>>100 most recent</option>
|
|
<option value="250" <%= filters.limit === '250' ? 'selected' : '' %>>250 most recent</option>
|
|
<option value="500" <%= filters.limit === '500' ? 'selected' : '' %>>500 most recent</option>
|
|
</select>
|
|
</label>
|
|
<a class="button subtle" href="/admin/logs">Reset</a>
|
|
<a class="button subtle" href="<%= `/admin/logs?range=${encodeURIComponent(filters.range)}&level=${encodeURIComponent(filters.level)}&limit=${encodeURIComponent(filters.limit)}` %>">Refresh</a>
|
|
<button type="button" class="button subtle" data-log-download>Download logs</button>
|
|
</div>
|
|
</div>
|
|
<div class="log-window" data-log-list>
|
|
<% if (!logs || !logs.length) { %>
|
|
<p class="hint">No log events yet.</p>
|
|
<% } else { %>
|
|
<% logs.forEach((log) => { %>
|
|
<details
|
|
class="log-entry level-<%= log.level %>"
|
|
data-log-entry
|
|
data-level="<%= log.level %>"
|
|
data-timestamp="<%= log.created_at %>"
|
|
data-search="<%= `${log.message} ${log.details || ""}`.toLowerCase() %>"
|
|
>
|
|
<summary>
|
|
<span class="log-marker" aria-hidden="true"></span>
|
|
<span class="log-message"><%= log.message %></span>
|
|
<span class="log-level-pill"><%= log.level %></span>
|
|
<span class="log-time"><%= new Date(log.created_at).toLocaleString() %></span>
|
|
</summary>
|
|
<% if (log.details) { %>
|
|
<pre class="log-details"><%= log.details %></pre>
|
|
<% } else { %>
|
|
<div class="log-details empty">No additional details.</div>
|
|
<% } %>
|
|
</details>
|
|
<% }) %>
|
|
<% } %>
|
|
</div>
|
|
</section>
|
|
<div class="modal-backdrop" data-log-modal aria-hidden="true">
|
|
<div class="modal">
|
|
<div class="modal-header">
|
|
<h3>Download logs</h3>
|
|
<button type="button" class="icon-button" data-modal-close aria-label="Close">
|
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M6 6l12 12M18 6l-12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<form method="get" action="/admin/logs/download" class="form-grid">
|
|
<div class="field">
|
|
<label>Timespan</label>
|
|
<select name="range">
|
|
<option value="all">All time</option>
|
|
<option value="<%= 5 * 60 * 1000 %>">Last 5 minutes</option>
|
|
<option value="<%= 60 * 60 * 1000 %>">Last hour</option>
|
|
<option value="<%= 24 * 60 * 60 * 1000 %>">Last 24 hours</option>
|
|
<option value="<%= 7 * 24 * 60 * 60 * 1000 %>">Last week</option>
|
|
<option value="<%= 30 * 24 * 60 * 60 * 1000 %>">Last month</option>
|
|
</select>
|
|
</div>
|
|
<div class="field full">
|
|
<label>Severities</label>
|
|
<div class="checkbox-grid">
|
|
<label><input type="checkbox" name="level" value="error" /> Error</label>
|
|
<label><input type="checkbox" name="level" value="warn" /> Warning</label>
|
|
<label><input type="checkbox" name="level" value="info" /> Info</label>
|
|
<label><input type="checkbox" name="level" value="debug" /> Debug</label>
|
|
</div>
|
|
<p class="hint">Leave unchecked for all severities.</p>
|
|
</div>
|
|
<div class="field">
|
|
<label>Entries</label>
|
|
<select name="limit">
|
|
<option value="50">50 most recent</option>
|
|
<option value="100">100 most recent</option>
|
|
<option value="250">250 most recent</option>
|
|
<option value="500">500 most recent</option>
|
|
<option value="all">All entries</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="button subtle" data-modal-close>Cancel</button>
|
|
<button type="submit" class="button">Download</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<%- include("partials/layout-bottom") %>
|