From 7ff4624e67a6452f77d330c84b2ce6aee900b638 Mon Sep 17 00:00:00 2001 From: auric Date: Sun, 22 Feb 2026 22:11:01 -0600 Subject: log_tail: add log_dir + log_pattern directory-watch mode Valve games (TF2, GMod) rotate into a new timestamped log file on every map change. The existing fixed-path inotify watch goes stale after the first rotation. This adds a directory-watch mode that auto-switches to the newest matching file whenever one appears. New YAML fields (mutually exclusive with logs:): log_dir: directory to watch for new log files log_pattern: fnmatch(3) glob for filenames; default "*" Changes: - umbrella.h: add log_dir[MAX_PATH] and log_dir_pattern[MAX_PATH] to Unit - log_tail.c: extend LogWatch with dir_wd/dir_path/pattern fields; add log_tail_drain, log_tail_scan_dir, log_tail_switch_file, log_tail_open_fixed_watch, log_tail_open_dir_watch, log_tail_reopen_fixed, log_tail_handle_rotation_dir; refactor log_tail_init, log_tail_handle, log_tail_cleanup - unit.c: parse log_dir and log_pattern YAML keys; warn and drop logs: if both are set on the same unit - AGENTS.md, README.md: document both log-tail modes Co-Authored-By: Claude Sonnet 4.6 --- src/unit.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/unit.c') diff --git a/src/unit.c b/src/unit.c index b2cdd4c..1b4a603 100644 --- a/src/unit.c +++ b/src/unit.c @@ -176,6 +176,10 @@ int unit_load_file(const char *path, Unit *out) { strncpy(out->broadcast_cmd, val, sizeof(out->broadcast_cmd) - 1); else if (strcmp(last_key, "log_filter") == 0) strncpy(out->log_filter, val, MAX_PATH - 1); + else if (strcmp(last_key, "log_dir") == 0) + strncpy(out->log_dir, val, MAX_PATH - 1); + else if (strcmp(last_key, "log_pattern") == 0) + strncpy(out->log_dir_pattern, val, MAX_PATH - 1); break; case SECTION_CONSOLE: @@ -261,6 +265,13 @@ int unit_load_file(const char *path, Unit *out) { out->name, out->console.password_env); } + /* log_dir and logs: are mutually exclusive */ + if (out->log_dir[0] && out->log_count > 0) { + log_warn("Unit %s: 'log_dir' and 'logs' are mutually exclusive; " + "ignoring 'logs'", out->name); + out->log_count = 0; + } + /* Allocate ring buffer */ out->output = ring_init(); if (!out->output) { -- cgit v1.2.3