ENHANCEMENT: allow excluding containers from stats collection entirely, not just from display
Context
The containers plugin opens a persistent stats stream and a background thread for
every container, unconditionally, and only afterwards discards the ones the user
filtered out with show= / hide=.
One fetcher is constructed per container in DockerExtension.update()
(glances/plugins/containers/engines/docker.py:311-317), straight from the
unfiltered list built at line 298 / 309:
# Start new thread for new container
for container in containers:
if container.id not in self.stats_fetchers:
...
self.stats_fetchers[container.id] = DockerStatsFetcher(container)and each fetcher immediately opens a streaming GET /containers/{id}/stats
(docker.py:53-55):
# Threaded Streamer
stats_iterable = container.stats(decode=True)
self._streamer = ThreadedIterableStreamer(stats_iterable, initial_stream_value={})The user's filter is applied only once those stats are already collected, in
ContainersPlugin.update() (glances/plugins/containers/__init__.py:254-270):
def is_key_in_container_and_hidden(container):
return (key := container.get('key')) in container and self.is_hide(nativestr(container.get(key)))
...
_, containers = watcher.update(all_tag=self._all_tag()) # stats already streaming
...
for container in get_containers_from_updated_watcher(watcher)
if not is_key_in_container_and_hidden(container)So a user who has explicitly told Glances to watch a subset still pays the full cost — one stream, one thread, and the daemon-side stats collection — for every container on the host.
Measured here (Glances 4.5.6, Docker 29.7.2, Arch Linux, 44 running containers):
69 open connections to /var/run/docker.sock, all owned by the single Glances
process. Stable across a full docker.service restart (re-measured at 69
afterwards).
This is the same axis as #3559 (containers plugin cost at ~60 containers). That issue reduced the per-update inspect cost; this one is about not doing the work at all for containers the user does not want.
Verified against develop and develop-v5: docker.py and
containers/__init__.py are byte-identical on the two branches (cmp clean),
so one patch covers both.
Proposal
Add a new opt-in config key to [containers] — name up for discussion, e.g.:
[containers]
# Containers to not monitor at all (comma-separated names or regexes).
# Unlike hide=, these are never polled: no stats stream, no thread.
no_stats=transmission_wireguard,some-other-containermatched before the fetcher is constructed in DockerExtension.update(), so no
stream is ever opened for them.
Deliberately not proposing a change to hide= semantics. hide= /show= are
documented as display filters, and hidden containers are still returned by
/api/4/containers. Making them skip collection would silently drop them from the
REST API and break existing dashboards. A separate key keeps that contract intact
and makes the intent explicit at the call site.
Scope
In scope: the fetcher-creation path in
glances/plugins/containers/engines/docker.py (DockerExtension.update()), the
new config key and its accessor on ContainersPlugin, the default
conf/glances.conf comment block, plus unit tests.
Out of scope:
hide=/show=behaviour — unchanged.- The containers plugin model, the TUI, and the WebUI. A container excluded via the new key simply never appears in the stats list, exactly as if it were not running.
engines/lxd.py.engines/podman.pyhas the same shape (PodmanContainerStatsFetchercreated per container atpodman.py:358), so the same change applies there — but I've left it out of scope rather than assume you want it in the same patch. Happy to include it if you'd prefer parity.
Non-regression requirements
- With the new key unset (the default), behaviour and open-connection count are identical to today.
hide=andshow=keep filtering display only, and hidden containers keep appearing in/api/4/containers.- A container matched by the new key opens no stats stream and starts no thread; its fetcher is torn down if the key is added and the config reloaded.
- Adding or removing a container from the key does not leak fetcher threads —
the existing
absent_containersteardown path (docker.py:320-328) must still run for excluded containers.
Corroborating case
The reason I went looking: haugene/transmission-wireguard moves eth0 out of the
container's Docker-managed netns as its VPN kill-switch, so dockerd cannot resolve
the interface for stats and logs an error line per stats sample:
dockerd: level=error msg="collecting stats for container /transmission_wireguard: \
failed to retrieve the statistics for eth0 in netns /var/run/docker/netns/...: Link not found"With Glances streaming, that is ~1 line/second — 375,816 lines in 4 days here.
Docker has no daemon-side switch for it (docker/distribution#3216, closed with no
fix), and hide=transmission_wireguard does not help for the reason above: the
stream keeps running. I've reported the interface naming upstream to the image
(haugene/docker-transmission-wireguard#19) and silenced the message locally with a
systemd LogFilterPatterns= drop-in, so this is not a request to fix Docker's
logging — it's just a concrete case where "stop polling this container" is the only
thing that actually addresses the cause, and there is currently no way to express it.
Source: nicolargo/glances