Exclude virtual interfaces from network stats
Some checks are pending
Release 3X-UI / Analyze Go code (push) Waiting to run
Release 3X-UI / build (386) (push) Blocked by required conditions
Release 3X-UI / build (amd64) (push) Blocked by required conditions
Release 3X-UI / build (arm64) (push) Blocked by required conditions
Release 3X-UI / build (armv5) (push) Blocked by required conditions
Release 3X-UI / build (armv6) (push) Blocked by required conditions
Release 3X-UI / build (armv7) (push) Blocked by required conditions
Release 3X-UI / build (s390x) (push) Blocked by required conditions
Release 3X-UI / Build for Windows (push) Blocked by required conditions

Switch net.IOCounters to per-interface mode and aggregate traffic while excluding loopback and common virtual/tunnel interfaces. Adds isVirtualInterface helper to filter interfaces by exact names and prefixes (docker, veth, tun, wg, tailscale, etc.), sums BytesSent/BytesRecv across valid interfaces, and assigns the totals to status.NetTraffic. Removes the previous warning branch when no counters were found and preserves NetIO rate calculations using lastStatus.
This commit is contained in:
MHSanaei 2026-05-06 17:28:41 +02:00
parent 9be11e109e
commit ad30298700
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A

View file

@ -315,13 +315,21 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
} }
// Network stats // Network stats
ioStats, err := net.IOCounters(false) ioStats, err := net.IOCounters(true)
if err != nil { if err != nil {
logger.Warning("get io counters failed:", err) logger.Warning("get io counters failed:", err)
} else if len(ioStats) > 0 { } else {
ioStat := ioStats[0] var totalSent, totalRecv uint64
status.NetTraffic.Sent = ioStat.BytesSent for _, iface := range ioStats {
status.NetTraffic.Recv = ioStat.BytesRecv name := strings.ToLower(iface.Name)
if isVirtualInterface(name) {
continue
}
totalSent += iface.BytesSent
totalRecv += iface.BytesRecv
}
status.NetTraffic.Sent = totalSent
status.NetTraffic.Recv = totalRecv
if lastStatus != nil { if lastStatus != nil {
duration := now.Sub(lastStatus.T) duration := now.Sub(lastStatus.T)
@ -331,8 +339,6 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
status.NetIO.Up = up status.NetIO.Up = up
status.NetIO.Down = down status.NetIO.Down = down
} }
} else {
logger.Warning("can not find io counters")
} }
// TCP/UDP connections // TCP/UDP connections
@ -860,6 +866,34 @@ func (s *ServerService) GetXrayLogs(
return entries return entries
} }
// isVirtualInterface returns true for loopback and virtual/tunnel interfaces
// that should be excluded from network traffic statistics.
func isVirtualInterface(name string) bool {
// Exact matches
if name == "lo" || name == "lo0" {
return true
}
// Prefix matches for virtual/tunnel interfaces
virtualPrefixes := []string{
"loopback",
"docker",
"br-",
"veth",
"virbr",
"tun",
"tap",
"wg",
"tailscale",
"zt",
}
for _, prefix := range virtualPrefixes {
if strings.HasPrefix(name, prefix) {
return true
}
}
return false
}
func logEntryContains(line string, suffixes []string) bool { func logEntryContains(line string, suffixes []string) bool {
for _, sfx := range suffixes { for _, sfx := range suffixes {
if strings.Contains(line, sfx+"]") { if strings.Contains(line, sfx+"]") {