152 lines
6.5 KiB
HTML
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}}
|