Files
vibedns/web/templates/pages/querylog.html
T
2026-08-16 21:18:45 -05:00

152 lines
6.5 KiB
HTML

{{define "content"}}
{{$f := .Data.Filter}}{{$csrf := .CSRF}}
<div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-4">
<div>
<h1 class="page-title">Query Log</h1>
<p class="text-body-secondary mb-0">
Every query this server answered, when logging is enabled.
</p>
</div>
<div class="d-flex flex-wrap gap-2">
<a href="/settings/logging" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-gear me-1"></i>Logging settings
</a>
{{template "confirmform" dict
"Action" "/querylog/clear" "CSRF" $csrf
"Label" "Clear log" "Icon" "bi-trash"
"Class" "btn btn-sm btn-outline-danger"
"Message" "Delete every row in the query log? This cannot be undone."}}
</div>
</div>
{{if not .Data.Enabled}}
<div class="alert alert-warning d-flex align-items-start gap-2">
<i class="bi bi-exclamation-triangle mt-1"></i>
<div>
Query logging is turned off, so no new queries are being recorded.
<a href="/settings/logging" class="alert-link">Turn it on</a> to populate this page and the
dashboard charts.
</div>
</div>
{{end}}
{{if gt .Data.Stats.Dropped 0}}
<div class="alert alert-warning d-flex align-items-start gap-2">
<i class="bi bi-speedometer mt-1"></i>
<div>
{{num .Data.Stats.Dropped}} log entries were dropped because the writer could not keep up.
Query answering is never delayed by logging, so under sustained load some records are
discarded rather than queued.
</div>
</div>
{{end}}
<div class="card">
<div class="card-body">
<form method="get" data-autosubmit class="row g-2 align-items-end mb-3">
<div class="col-12 col-md-3">
<label class="form-label small" for="fDomain">Domain</label>
<input type="search" class="form-control form-control-sm" id="fDomain" name="domain"
value="{{$f.Domain}}" placeholder="example.com">
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fClient">Client IP</label>
<input type="search" class="form-control form-control-sm" id="fClient" name="client"
value="{{$f.ClientIP}}" placeholder="192.168.1.10">
</div>
<div class="col-6 col-md-1">
<label class="form-label small" for="fType">Type</label>
<input type="text" class="form-control form-control-sm" id="fType" name="type"
value="{{$f.QType}}" placeholder="A">
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fStatus">Status</label>
<select class="form-select form-select-sm" id="fStatus" name="blocked">
<option value="">All</option>
<option value="blocked" {{if eq $f.Blocked "blocked"}}selected{{end}}>Blocked</option>
<option value="allowed" {{if eq $f.Blocked "allowed"}}selected{{end}}>Allowed</option>
</select>
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fSource">Source</label>
<select class="form-select form-select-sm" id="fSource" name="source">
<option value="">All</option>
{{range list "authoritative" "cache" "stale" "recursive" "blocked" "refused" "ratelimited" "error"}}
<option value="{{.}}" {{if eq . $f.Source}}selected{{end}}>{{title .}}</option>
{{end}}
</select>
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fNetwork">Network</label>
<select class="form-select form-select-sm" id="fNetwork" name="network">
<option value="">All</option>
{{range .Data.Networks}}
<option value="{{.ID}}" {{if eq .ID $f.NetworkID}}selected{{end}}>{{.Name}}</option>
{{end}}
</select>
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fFrom">From</label>
<input type="date" class="form-control form-control-sm" id="fFrom" name="from"
value="{{if not (zeroTime $f.From)}}{{dateOnly $f.From}}{{end}}">
</div>
<div class="col-6 col-md-2">
<label class="form-label small" for="fTo">To</label>
<input type="date" class="form-control form-control-sm" id="fTo" name="to"
value="{{if not (zeroTime $f.To)}}{{dateOnly $f.To}}{{end}}">
</div>
<div class="col-auto">
<noscript><button class="btn btn-sm btn-outline-secondary" type="submit">Apply</button></noscript>
<a href="/querylog" class="btn btn-sm btn-link">Clear filters</a>
</div>
</form>
{{if .Data.Entries}}
<div class="table-responsive">
<table class="table table-hover align-middle table-compact">
<thead>
<tr>
<th>Time</th><th>Client</th><th>Network</th><th>Query</th><th>Type</th>
<th>Result</th><th>Source</th><th>Matched</th><th class="text-end">Took</th>
</tr>
</thead>
<tbody>
{{range .Data.Entries}}
<tr>
<td class="small text-nowrap" title="{{datetime .Timestamp}}">{{timeOnly .Timestamp}}</td>
<td class="mono small">{{.ClientIP}}</td>
<td class="small text-body-secondary">{{default "—" .NetworkName}}</td>
<td class="mono truncate-cell" title="{{.QName}}">{{trimDot .QName}}</td>
<td><span class="type-chip {{typeBadge .QType}}">{{.QType}}</span></td>
<td>
<span class="badge {{rcodeBadge .Rcode}}">{{.Rcode}}</span>
{{if .Blocked}}<span class="badge text-bg-danger ms-1">blocked</span>{{end}}
</td>
<td><span class="badge {{sourceBadge .Source}}">{{.Source}}</span></td>
<td class="small">
{{if .Blocked}}
<span class="text-body-secondary">{{.BlacklistName}}</span>
{{if .MatchedRule}}<div class="mono text-body-secondary">{{.MatchedRule}}</div>{{end}}
{{else if .CacheHit}}
<span class="text-body-secondary">cache hit</span>
{{else}}
<span class="text-body-secondary"></span>
{{end}}
</td>
<td class="text-end small">{{ms .DurationMS}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{template "pagination" dict "P" .Data.Pagination "Q" .Query}}
{{else}}
{{template "empty" dict "Icon" "bi-journal-text" "Title" "No queries match"
"Message" "Either nothing has been logged yet, or the filters above exclude everything. Clear the filters to see the whole log."}}
{{end}}
</div>
</div>
{{end}}