From c0c031a5e44c1c52ae5b304b9929ee9cd2c4af45 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 23 Sep 2026 23:19:31 +0200 Subject: [PATCH] swarm-bao: let the journald receiver read the host-linked journal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The container's collector has never shipped a line. `journalctl --follow` — which the journald receiver passes unconditionally — scopes itself to the current boot unless `--merge` is given too, and `--link-journal=host` makes /var/log/journal the HOST's journal tree, where this container's current boot has no entry. journalctl exited 1 with "No journal boot entry found for the specified boot (+0)" and the receiver respawned it every ~2s, so nothing was ever read and nothing was ever exported. `merge = true` is the receiver's key for `--merge` (buildArgs() in pkg/stanza/operator/input/journald/config_linux.go at tag receiver/journaldreceiver/v0.151.0, the deployed collector's version), and --merge is what clears the implicit boot scope in journalctl.c (systemd v260.4, the version on the host). The module-eval arm pins both halves: the boot filter is gone AND the directory is still the host-linked one — either alone is satisfiable by the broken config. --- nix/host-modules/swarm-bao.nix | 6 ++++++ nix/module-eval/bao-otel-collector.nix | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/nix/host-modules/swarm-bao.nix b/nix/host-modules/swarm-bao.nix index fcf48209..43dd4368 100644 --- a/nix/host-modules/swarm-bao.nix +++ b/nix/host-modules/swarm-bao.nix @@ -2530,6 +2530,12 @@ in # this machine id. Dropping this line leaves a collector that # validates, starts, reports healthy and forwards nothing. directory = "/var/log/journal"; + # ⚠️ `--merge`, and it is what makes this receiver read + # anything at all: `journalctl --follow` scopes itself to the + # current boot, which has no entry under the host's journal + # tree — so every start died with "No journal boot entry found + # for the specified boot (+0)" in a ~2s crash-loop. + merge = true; storage = "file_storage"; }; diff --git a/nix/module-eval/bao-otel-collector.nix b/nix/module-eval/bao-otel-collector.nix index ebd1d198..4ec0d472 100644 --- a/nix/module-eval/bao-otel-collector.nix +++ b/nix/module-eval/bao-otel-collector.nix @@ -246,6 +246,25 @@ let && p.exporters == [ "otlphttp" ] && s ? exporters.otlphttp; } + { + # 🩸 The receiver read NOTHING before this, on every deploy there has + # ever been: `journalctl --follow` (the receiver passes `--follow` + # unconditionally) scopes itself to the current boot unless `--merge` is + # also given, and under `--link-journal=host` the directory below is the + # HOST's journal tree, where this container's current boot has no entry. + # journalctl exited 1 with "No journal boot entry found for the specified + # boot (+0)" and the receiver restarted it every ~2s forever. + # + # Both halves, because each alone is satisfiable by the broken config: + # `merge` is only a fix while the directory stays the host-linked one, + # and the directory is only readable while `merge` clears the boot scope. + name = "the store's forwarder reads the host-linked journal without a boot filter"; + ok = + let + j = (baoForwarder baoWithCollector).settings.receivers.journald; + in + (j.merge or false) == true && j.directory == "/var/log/journal"; + } { # The whole journal, which is what the shared collector's unit allowlist # is not. A `units` list here would render and deploy perfectly while