Skip to content

Commit c638b77

Browse files
MaurUppiclaude
andcommitted
fix(udp): demote normal UdpEndpoint EOF exits from Warn to Debug
T4 added Warn logging for all UdpEndpoint.start() read-loop exits. In production this caused ~100 Warn/min noise from QUIC (UDP/443) sessions on mask.icloud.com that close normally via EOF — a 1:1 ratio with new UDP connection establishments, confirming these are expected QUIC session teardowns, not errors. Add isUdpEndpointNormalClose() to classify: - io.EOF → normal peer close (QUIC session end, NatTimeout expiry) - "use of closed network connection" → Reset(0) cleanup race, expected - everything else → real errors, keep Warn EOF/closed-connection exits now log at Debug; genuine errors (broken pipe, connection reset, etc.) remain at Warn for observability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7bae9c5 commit c638b77

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

control/udp_endpoint_pool.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ package control
88
import (
99
"context"
1010
"fmt"
11+
"io"
1112
"net/netip"
13+
"strings"
1214
"sync"
1315
"time"
1416

@@ -38,13 +40,35 @@ type UdpEndpoint struct {
3840
DialTarget string
3941
}
4042

43+
// isUdpEndpointNormalClose reports whether err represents a normal (non-error) endpoint
44+
// teardown: peer EOF, NatTimeout expiry ("use of closed network connection"), or an explicit
45+
// local close triggered by Reset(0) cleanup.
46+
func isUdpEndpointNormalClose(err error) bool {
47+
if err == nil {
48+
return true
49+
}
50+
if err == io.EOF {
51+
return true
52+
}
53+
// "use of closed network connection" is returned when Reset(0) fires ue.Close() just
54+
// before ReadFrom returns; this is the expected cleanup path, not an error.
55+
if strings.Contains(err.Error(), "use of closed network connection") {
56+
return true
57+
}
58+
return false
59+
}
60+
4161
func (ue *UdpEndpoint) start() {
4262
buf := pool.GetFullCap(consts.EthernetMtu)
4363
defer pool.Put(buf)
4464
for {
4565
n, from, err := ue.conn.ReadFrom(buf[:])
4666
if err != nil {
47-
logrus.WithError(err).Warnln("UdpEndpoint read loop exited")
67+
if !isUdpEndpointNormalClose(err) {
68+
logrus.WithError(err).Warnln("UdpEndpoint read loop exited")
69+
} else {
70+
logrus.WithError(err).Debugln("UdpEndpoint read loop exited")
71+
}
4872
break
4973
}
5074
ue.mu.Lock()

0 commit comments

Comments
 (0)