Repository navigation
fix(containers): aggregate network stats over all container interfaces (#3669) - #3670
Conversation
_get_network_stats() read the container network counters from a single hardcoded interface. The Docker stats endpoint returns one entry per container interface, so a container attached to several networks gets eth0, eth1... and everything past eth0 was silently dropped, making the reported RX/TX rates too low. Sum rx_bytes/tx_bytes across all the interfaces instead. Loopback is excluded, since Docker-API-compatible runtimes have been observed to report it and its traffic would inflate the totals. Interfaces with missing counters are skipped rather than aborting the whole method, so one malformed interface no longer discards the valid ones. None is still returned when nothing usable remains, keeping --network host containers unchanged. The output contract is untouched: same keys, same types, same units. Fixes nicolargo#3669
…arry Matches the convention in tests/test_plugin_sensors.py and clears the docstring findings Codacy raised on the PR.
|
Two red checks on this PR, both traced — neither is a defect in the change, but you should decide on the second one. AppVeyor — red on every open PR right now, not just this one: #3667, #3665 and #3613 all show Codacy — "13 new issues" — I reproduced the exact number locally. All 13 are 4 attribute injections in
I have not "fixed" this, because both available fixes are your call and the repo has no precedent either way:
Say which you prefer and I'll push it. Meanwhile I pushed the class docstrings the sibling Also still open from the PR description: the decision point in the issue (I implemented (a) leave the negative delta as is, reasoning in the description), and whether you want the companion |
|
Thanks for the PR @ntdatt812 Just merged into develop. I just remove the line in the NEWS.md file because the patch will be release in Glances 4.5.7, not 4.5.6. |
Description
Fixes #3669.
DockerStatsFetcher._get_network_stats()read the container network counters from asingle hardcoded interface:
The Docker stats endpoint returns one entry per container interface, so a container
attached to several networks (
docker network connect, or several networks in a Composefile) gets
eth0,eth1, … and everything pasteth0was silently dropped. ReportedRX/TX for those containers was too low.
The method now sums
rx_bytes/tx_bytesacross all interfaces. Its output contract isunchanged: same keys, same types, same units.
Two deliberate choices, as discussed in the issue:
lois excluded. The Docker daemon does not normally report loopback innetworks,but Docker-API-compatible runtimes have been observed to, and loopback traffic would
massively inflate the totals.
eth0aborted the whole method; now one malformed interface among several no longerdiscards the valid ones.
Noneis still returned when nothing usable remains, so--network hostcontainers (nonetworkskey) behave exactly as before.On the decision point raised in the issue
The issue asked not to decide alone between (a) leave as is and (b) clamp the delta
to zero, given that attaching/detaching a network between two samples changes the
interface set and can produce one negative
rx/txdelta.This PR implements (a), for two reasons:
reset. (b) would silently swallow that pre-existing signal too, which changes behaviour
for a case that is not in the scope of this issue.
out to matter in practice, clamping is better addressed once for all cumulative
counters than locally here.
Happy to switch to (b) if you prefer.
Tests
New file
tests/test_plugin_containers.py, 9 cases, pytest style to match the siblingtest_plugin_*.pyfiles.DockerStatsFetcher.__init__opens a live stats stream, so theinstance is built via
__new__with the two attributes the method reads injected.loexcludednetworkskey)NonenetworksdictNoneNonerx/txare the summed deltas,time_since_updatepresentrx/tx/time_since_updatekeysVerified the tests actually pin the bug — against the unpatched
docker.py, exactly thetwo cases that target it fail and the seven regression guards pass:
With the patch:
9 passed.Regression run
Full suite before and after, same machine (Windows 11, Python 3.14, 1 running container):
The 72 pre-existing failures/errors —
test_restful.py,test_xmlrpc.py,test_mcp.py,test_browser_restful.py,test_amp_secure_popen.py,test_webui.py,test_perf.py, allserver/WebUI tests that need a chromedriver and a POSIX socket — are identical line for
line before and after. The 9 new tests account for the passed count.
The single delta is
test_memoryleak.py::test_memoryleak_no_history(
assert memory_leak < 15000, got 15524). It is not caused by this change:The file passes on its own with the patch applied.
Its measurement is unstable on this machine, and it exceeds its own threshold on
unpatched
develop. Three runs each, reading the value the test itself logs:developThe unpatched spread is 7 948 – 32 480 B, a 4× range against a hard-coded 15 000 B
threshold, and the unpatched maximum is the largest of all six runs.
Isolating the changed method removes the ambiguity. Driving both implementations
200 000 times under
tracemallocwith the same single-interface payload:Neither retains anything — that residue is tracemalloc's own bookkeeping — and the new
form retains marginally less. The memory-leak test performs ~13 calls per run, so the
per-call difference is well under a byte.
Flagging the threshold separately since it is unrelated to this PR: on a machine with any
background load,
test_memoryleak_no_historylooks like it can fail on a clean checkout.Happy to open a separate issue if that is useful.
ruff formatandruff checkare clean on both touched files.rstcheck NEWS.rstreportsthe same 8 pre-existing issues before and after, shifted by the one added line.
Branches
Applied to
develop. I re-verified the branch parity the issue asked about rather thanassuming it:
glances/plugins/containers/engines/docker.pyhas blob SHAc818def749329c9b2d00171c43cb2f2739fac5f4on bothdevelopanddevelop-v5, so thecherry-pick to
develop-v5is clean. Say the word and I'll open the companion PR.Resume
eth0#3669