query log batching: one transaction per flush interval, not per query
Gates / frontend (push) Successful in 1m18s
Gates / test (push) Successful in 2m46s
Gates / test-aarch64 (push) Successful in 7m33s
Gates / package (push) Successful in 5m34s
Gates / container (push) Successful in 17s
CI / gates (push) Successful in 16m16s
Gates / frontend (push) Successful in 1m8s
Gates / container (push) Successful in 9s
Release / gates (push) Successful in 9m15s
Release / guard (push) Successful in 19s
Gates / test (push) Successful in 1m34s
Gates / test-aarch64 (push) Successful in 6m46s
Gates / package (push) Successful in 39s
Release / publish (push) Failing after 4m7s
Gates / frontend (push) Successful in 1m18s
Gates / test (push) Successful in 2m46s
Gates / test-aarch64 (push) Successful in 7m33s
Gates / package (push) Successful in 5m34s
Gates / container (push) Successful in 17s
CI / gates (push) Successful in 16m16s
Gates / frontend (push) Successful in 1m8s
Gates / container (push) Successful in 9s
Release / gates (push) Successful in 9m15s
Release / guard (push) Successful in 19s
Gates / test (push) Successful in 1m34s
Gates / test-aarch64 (push) Successful in 6m46s
Gates / package (push) Successful in 39s
Release / publish (push) Failing after 4m7s
This commit is contained in:
@@ -231,6 +231,10 @@ pub const Logging = struct {
|
||||
level: LogLevel = .info,
|
||||
retention_days: u16 = 30,
|
||||
query_log_buffer_max: u32 = 10000,
|
||||
/// How long the query-log writer gathers entries before it commits them.
|
||||
/// `0` does not wait at all: it flushes the entry that woke the writer plus
|
||||
/// whatever is already queued.
|
||||
query_log_flush_interval_s: u16 = 60,
|
||||
hide_domains: bool = false,
|
||||
hide_client_ips: bool = false,
|
||||
output: LogOutput = .stderr,
|
||||
@@ -565,6 +569,7 @@ const expected_keys = [_][]const u8{
|
||||
"logging.max_size_mb",
|
||||
"logging.output",
|
||||
"logging.query_log_buffer_max",
|
||||
"logging.query_log_flush_interval_s",
|
||||
"logging.retention_days",
|
||||
"upstream.attempt_timeout_ms",
|
||||
"upstream.read_timeout_ms",
|
||||
@@ -657,6 +662,7 @@ test "toSettings and fromSettings round-trip a non-default config" {
|
||||
.level = .err,
|
||||
.retention_days = 41,
|
||||
.query_log_buffer_max = 43,
|
||||
.query_log_flush_interval_s = 44,
|
||||
.hide_domains = true,
|
||||
.hide_client_ips = true,
|
||||
.output = .file,
|
||||
|
||||
@@ -93,6 +93,7 @@ pub const ValidateError = error{
|
||||
BadTtl,
|
||||
BadCacheSize,
|
||||
BadRetention,
|
||||
BadFlushInterval,
|
||||
BadLogRotation,
|
||||
BadDiskThresholds,
|
||||
BadRateLimit,
|
||||
@@ -335,6 +336,11 @@ const max_rate_window_seconds = 3_600;
|
||||
/// the box, and nxdns does not try to know that.
|
||||
const max_boot_entries = 1_000_000;
|
||||
|
||||
/// The ceiling on the query-log flush window. An hour of queries is already
|
||||
/// more history than a crash is allowed to cost; beyond that the setting stops
|
||||
/// being a batching knob and becomes a way to lose a working day of rows.
|
||||
const max_flush_interval_s = 3_600;
|
||||
|
||||
fn checkScalars(cfg: Config, diags: *Diagnostics) error{OutOfMemory}!void {
|
||||
const up = cfg.upstream;
|
||||
try checkTimeout(diags, up.attempt_timeout_ms, "upstream.attempt_timeout_ms");
|
||||
@@ -464,6 +470,16 @@ fn checkScalars(cfg: Config, diags: *Diagnostics) error{OutOfMemory}!void {
|
||||
.{ max_boot_entries, cfg.logging.query_log_buffer_max },
|
||||
);
|
||||
}
|
||||
// No floor: 0 is the documented "do not wait" setting, not a mistake.
|
||||
if (cfg.logging.query_log_flush_interval_s > max_flush_interval_s) {
|
||||
try diags.add(
|
||||
error.BadFlushInterval,
|
||||
"logging.query_log_flush_interval_s",
|
||||
.{},
|
||||
"must be at most {d}, got {d}",
|
||||
.{ max_flush_interval_s, cfg.logging.query_log_flush_interval_s },
|
||||
);
|
||||
}
|
||||
if (cfg.logging.max_size_mb < 1) {
|
||||
try diags.add(error.BadLogRotation, "logging.max_size_mb", .{}, "must be at least 1", .{});
|
||||
}
|
||||
@@ -1946,6 +1962,22 @@ test "error.BadRetention" {
|
||||
try expectProblem(huge_buffer, error.BadRetention, "logging.query_log_buffer_max");
|
||||
}
|
||||
|
||||
test "error.BadFlushInterval" {
|
||||
var cfg = baseConfig();
|
||||
cfg.logging.query_log_flush_interval_s = 3601;
|
||||
try expectProblem(cfg, error.BadFlushInterval, "logging.query_log_flush_interval_s");
|
||||
|
||||
// 0 is the "do not wait" setting and 3600 is the ceiling itself: both are
|
||||
// legal, and a floor check would reject the first.
|
||||
var immediate = baseConfig();
|
||||
immediate.logging.query_log_flush_interval_s = 0;
|
||||
try expectClean(immediate);
|
||||
|
||||
var edge = baseConfig();
|
||||
edge.logging.query_log_flush_interval_s = max_flush_interval_s;
|
||||
try expectClean(edge);
|
||||
}
|
||||
|
||||
test "error.BadLogRotation" {
|
||||
var cfg = baseConfig();
|
||||
cfg.logging.max_files = 0;
|
||||
|
||||
Reference in New Issue
Block a user