feat(mcp): search_container_logs takes a Swarm service's name and searches every task it has run (#5468)
#5468 "Log search by service name: searching "steward_app" refuses because every deploy makes a new container name". search_container_logs(container="steward_app") was refused, because no container carries the service's own name and five task containers partly matched. Now a service's name reaches every task container Steward holds anything for, live and removed (docker_svc.service_containers, as the service page's logs already do), so one search spans deploys. Each match carries the slot and task_id that wrote it, and the reply names the service and how many tasks were searched. A container named exactly what was asked still takes precedence. A miss that partly matches task containers now names their services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -356,9 +356,12 @@ def scaled_bars(values: list, floor: float) -> dict:
|
||||
|
||||
|
||||
async def search_logs(db, *, since, host_id: str | None = None, name: str | None = None,
|
||||
containers: list[tuple[str, str]] | None = None,
|
||||
text: str = "", stream: str = "", before=None, limit: int = 50) -> list:
|
||||
"""Retained log lines matching a filter, newest first (limit + 1 fetched by callers
|
||||
that need to know whether more exist)."""
|
||||
that need to know whether more exist). `containers` keeps the lines of those
|
||||
(host_id, container_name) pairs: a swarm service's tasks (#5468)."""
|
||||
from sqlalchemy import tuple_
|
||||
stmt = (select(DockerLog.id, DockerLog.host_id, DockerLog.container_name,
|
||||
DockerLog.ts, DockerLog.stream, DockerLog.line)
|
||||
.where(DockerLog.ts >= since))
|
||||
@@ -366,6 +369,10 @@ async def search_logs(db, *, since, host_id: str | None = None, name: str | None
|
||||
stmt = stmt.where(DockerLog.host_id == host_id)
|
||||
if name:
|
||||
stmt = stmt.where(DockerLog.container_name == name)
|
||||
if containers is not None:
|
||||
if not containers:
|
||||
return []
|
||||
stmt = stmt.where(tuple_(DockerLog.host_id, DockerLog.container_name).in_(containers))
|
||||
if stream in ("stdout", "stderr"):
|
||||
stmt = stmt.where(DockerLog.stream == stream)
|
||||
if text:
|
||||
|
||||
Reference in New Issue
Block a user