milestone 28: query provenance — every logged query is exactly explainable
Gates / frontend (push) Successful in 1m36s
Gates / test (push) Successful in 1m56s
Gates / test-aarch64 (push) Successful in 7m37s
Gates / package (push) Successful in 9m12s
Gates / container (push) Successful in 13s
CI / gates (push) Successful in 19m4s
Gates / frontend (push) Successful in 1m36s
Gates / test (push) Successful in 1m56s
Gates / test-aarch64 (push) Successful in 7m37s
Gates / package (push) Successful in 9m12s
Gates / container (push) Successful in 13s
CI / gates (push) Successful in 19m4s
query rows gain qclass, rcode, group, policy action and reason, the matched rule or list entry with its source, cname and safe-search targets, route kind, forward zone, and the resolver that actually answered — the pool and local markers die. servfails are logged and name the resolver that lost; post-parse protocol refusals become rows. a detail page at /queries/:id renders the ordered explanation, and coverage watermarks distinguish an empty history from a missing one. the schema fingerprint changes: existing query history is recreated with the old file kept aside and the reset filed as a resolved diagnostic. fixes an oversized udp reply being rebuilt as noerror, which handed clients a truncated nxdomain as success.
This commit is contained in:
@@ -114,8 +114,10 @@ pub const Retention = struct {
|
||||
// still prunes through `Store.init`.
|
||||
if (store) |s| s.prune(io, now);
|
||||
|
||||
if (queries_repo.pruneOlderThan(database, cutoff)) |deleted| {
|
||||
add(&self.counters.rows_pruned, @intCast(deleted));
|
||||
// One operation, not two: the delete and the coverage watermark it
|
||||
// advances commit together or not at all (`queries_repo`).
|
||||
if (queries_repo.pruneOlderThan(database, cutoff)) |pruned| {
|
||||
add(&self.counters.rows_pruned, @intCast(pruned.deleted));
|
||||
maintenance(store, io, now, "prune", null);
|
||||
} else |err| {
|
||||
log.warn("retention prune before {d} failed: {s}", .{ cutoff, @errorName(err) });
|
||||
@@ -255,11 +257,23 @@ fn writeRows(database: *db.Db, timestamps: []const i64) !void {
|
||||
.domain = "example.com",
|
||||
.client_ip = "192.0.2.10",
|
||||
.qtype = 1,
|
||||
.qclass = 1,
|
||||
.rcode = 0,
|
||||
.blocked = false,
|
||||
.block_reason = null,
|
||||
.response_time_us = null,
|
||||
.cache_hit = null,
|
||||
.upstream = null,
|
||||
.group_id = 1,
|
||||
.group_name = "default",
|
||||
.policy_action = .allow,
|
||||
.policy_reason = .no_match,
|
||||
.matched = null,
|
||||
.source_id = null,
|
||||
.source_name = null,
|
||||
.cname_target = null,
|
||||
.safe_search_target = null,
|
||||
.route_kind = .upstream,
|
||||
.forward_zone = null,
|
||||
};
|
||||
}
|
||||
try writer.writeBatch(rows[0..timestamps.len]);
|
||||
|
||||
Reference in New Issue
Block a user