fix(container): Fix Podman 5.x Network Traffic Statistics Not Displaying (#991)

* fix(container): Added version parameter to accommodate Podman 5.x network statistics format

Modified the parseStats method to accept a version parameter, handling changes in Podman 5.x's network statistics data structure. When the version is 5.x, network traffic data is retrieved from the RxBytes/TxBytes fields of the Network interface.

* fix(container): Fixed Podman version detection logic to correctly retrieve network statistics

Addressed Podman version number parsing issues and improved version comparison logic to support all 4.x and below versions as well as 5.x and above versions

* fix(container): Resolved display formatting issues for network and disk I/O statistics

Handled default values when NetIO and BlockIO are null, and reformatted display strings to distinguish upstream/downstream traffic and read/write operations.

* fix: Why did I mess up the tag order?
This commit is contained in:
GT610
2026-01-06 23:44:54 +08:00
committed by GitHub
parent 7c35abe30e
commit 06ed38ff45
2 changed files with 36 additions and 10 deletions

View File

@@ -20,7 +20,7 @@ sealed class ContainerPs {
factory ContainerPs.fromRaw(String s, ContainerType typ) => typ.ps(s);
void parseStats(String s);
void parseStats(String s, [String? version]);
}
final class PodmanPs implements ContainerPs {
@@ -55,7 +55,7 @@ final class PodmanPs implements ContainerPs {
ContainerStatus get status => ContainerStatus.fromPodmanExited(exited);
@override
void parseStats(String s) {
void parseStats(String s, [String? version]) {
final stats = json.decode(s);
final cpuD = (stats['CPU'] as double? ?? 0).toStringAsFixed(1);
final cpuAvgD = (stats['AvgCPU'] as double? ?? 0).toStringAsFixed(1);
@@ -63,12 +63,32 @@ final class PodmanPs implements ContainerPs {
final memLimit = (stats['MemLimit'] as int? ?? 0).bytes2Str;
final memUsage = (stats['MemUsage'] as int? ?? 0).bytes2Str;
mem = '$memUsage / $memLimit';
final netIn = (stats['NetInput'] as int? ?? 0).bytes2Str;
final netOut = (stats['NetOutput'] as int? ?? 0).bytes2Str;
net = '$netIn / ↑ $netOut';
int netIn = 0;
int netOut = 0;
final majorVersion = version?.split('.').firstOrNull;
final majorVersionNum = majorVersion != null ? int.tryParse(majorVersion) : null;
// Podman 4.x and earlier use top-level NetInput/NetOutput fields.
// Podman 5.x changed network backend (Netavark) and uses nested
// Network.{iface}.RxBytes/TxBytes structure instead.
if (majorVersionNum == null || majorVersionNum <= 4) {
netIn = stats['NetInput'] as int? ?? 0;
netOut = stats['NetOutput'] as int? ?? 0;
} else if (majorVersionNum >= 5) {
final network = stats['Network'] as Map<String, dynamic>?;
if (network != null) {
for (final interface in network.values) {
netIn += interface['RxBytes'] as int? ?? 0;
netOut += interface['TxBytes'] as int? ?? 0;
}
}
}
net = '${netIn.bytes2Str} / ↑ ${netOut.bytes2Str}';
final diskIn = (stats['BlockInput'] as int? ?? 0).bytes2Str;
final diskOut = (stats['BlockOutput'] as int? ?? 0).bytes2Str;
disk = '${l10n.read} $diskOut / ${l10n.write} $diskIn';
disk = '${l10n.read} $diskIn / ${l10n.write} $diskOut';
}
factory PodmanPs.fromRawJson(String str) => PodmanPs.fromJson(json.decode(str));
@@ -125,12 +145,18 @@ final class DockerPs implements ContainerPs {
ContainerStatus get status => ContainerStatus.fromDockerState(state);
@override
void parseStats(String s) {
void parseStats(String s, [String? version]) {
final stats = json.decode(s);
cpu = stats['CPUPerc'];
mem = stats['MemUsage'];
net = stats['NetIO'];
disk = stats['BlockIO'];
final netIO = stats['NetIO'] as String? ?? '0B / 0B';
final netParts = netIO.split(' / ');
net = '${netParts.firstOrNull ?? '0B'} / ↑ ${netParts.length > 1 ? netParts[1] : '0B'}';
final blockIO = stats['BlockIO'] as String? ?? '0B / 0B';
final blockParts = blockIO.split(' / ');
disk = '${l10n.read} ${blockParts.firstOrNull ?? '0B'} / ${l10n.write} ${blockParts.length > 1 ? blockParts[1] : '0B'}';
}
/// CONTAINER ID NAMES IMAGE STATUS

View File

@@ -186,7 +186,7 @@ class ContainerNotifier extends _$ContainerNotifier {
(element) => element.contains(id.substring(0, 5)),
);
if (statsLine == null) continue;
item.parseStats(statsLine);
item.parseStats(statsLine, state.version);
}
} catch (e, trace) {
state = state.copyWith(