feat(syslog): devices through Swarm's ingress told apart by name; the send-to address is a setting (#6096)
CI / lint (push) Successful in 2s
CI / unit (push) Failing after 1m30s
CI / integration (push) Successful in 1m38s
CI / publish (push) Skipped

Through ingress every device arrives from Docker's own address, so a
source there is keyed by the hostname its lines carry (new column
sender, unique with address). The set-up help no longer guesses the
address from the web hostname: it shows the plugin's send_to setting,
covers ingress and host mode, ASUSTOR ADM, and both syslog formats.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 12:05:28 -04:00
co-authored by Claude Opus 5.5
parent d2926b6663
commit 0a647bbb82
11 changed files with 193 additions and 53 deletions
+5
View File
@@ -25,6 +25,10 @@ async def list_syslog_sources(state: str = "") -> dict:
"offered" (sending but not added: counted, not kept), "ignored";
empty for all.
A device whose lines reach Steward through Docker's own address (a port
published on Swarm's ingress) is told apart by the name its lines carry:
`through_docker` is true and `address` is Docker's, shared with the others.
Each gives its address, the host it is shown on, lines received in all
(`lines_total`) and, for an added source, in the last hour, when it was
last heard and its newest line. search_syslog searches the kept lines.
@@ -41,6 +45,7 @@ async def list_syslog_sources(state: str = "") -> dict:
hosts = {h.id: h.name for h in (await db.execute(select(Host))).scalars()}
return {"sources": [{
"source_id": s.id, "name": source_name(s), "address": s.address, "state": s.state,
"through_docker": bool(s.sender),
"host_id": s.host_id, "host_name": hosts.get(s.host_id), "calls_itself": s.hostname_seen or None,
"lines_total": s.lines_total, "lines_last_hour": per_hour.get(s.id, 0) if s.state == "accepted" else None,
"last_heard": iso(s.last_seen_at), "last_heard_age_s": age_s(s.last_seen_at, now),