mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
sockstats: switch label to enum
Makes it cheaper/simpler to persist values, and encourages reuse of labels as opposed to generating an arbitrary number. Updates tailscale/corp#9230 Updates #3363 Signed-off-by: Mihai Parparita <mihai@tailscale.com>
This commit is contained in:
parent
9687f3700d
commit
6ac6ddbb47
@ -119,10 +119,10 @@ func NewNoStart(opts Options) (_ *Auto, err error) {
|
||||
statusFunc: opts.Status,
|
||||
}
|
||||
c.authCtx, c.authCancel = context.WithCancel(context.Background())
|
||||
c.authCtx = sockstats.WithSockStats(c.authCtx, "controlclient.Auto:auth")
|
||||
c.authCtx = sockstats.WithSockStats(c.authCtx, sockstats.LabelControlClientAuto)
|
||||
|
||||
c.mapCtx, c.mapCancel = context.WithCancel(context.Background())
|
||||
c.mapCtx = sockstats.WithSockStats(c.mapCtx, "controlclient.Auto:map")
|
||||
c.mapCtx = sockstats.WithSockStats(c.mapCtx, sockstats.LabelControlClientAuto)
|
||||
|
||||
c.unregisterHealthWatch = health.RegisterWatcher(direct.ReportHealthChange)
|
||||
return c, nil
|
||||
@ -211,7 +211,7 @@ func (c *Auto) cancelAuth() {
|
||||
}
|
||||
if !c.closed {
|
||||
c.authCtx, c.authCancel = context.WithCancel(context.Background())
|
||||
c.authCtx = sockstats.WithSockStats(c.authCtx, "controlclient.Auto:auth")
|
||||
c.authCtx = sockstats.WithSockStats(c.authCtx, sockstats.LabelControlClientAuto)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
@ -222,7 +222,7 @@ func (c *Auto) cancelMapLocked() {
|
||||
}
|
||||
if !c.closed {
|
||||
c.mapCtx, c.mapCancel = context.WithCancel(context.Background())
|
||||
c.mapCtx = sockstats.WithSockStats(c.mapCtx, "controlclient.Auto:map")
|
||||
c.mapCtx = sockstats.WithSockStats(c.mapCtx, sockstats.LabelControlClientAuto)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ func (a *Dialer) dialHost(ctx context.Context, addr netip.Addr) (*ClientConn, er
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
ctx = sockstats.WithSockStats(ctx, "controlclient.Dialer")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelControlClientDialer)
|
||||
|
||||
// u80 and u443 are the URLs we'll try to hit over HTTP or HTTPS,
|
||||
// respectively, in order to do the HTTP upgrade to a net.Conn over which
|
||||
|
@ -616,7 +616,7 @@ type res struct {
|
||||
ctx, cancel := context.WithTimeout(ctx, dialNodeTimeout)
|
||||
defer cancel()
|
||||
|
||||
ctx = sockstats.WithSockStats(ctx, "derphttp.Client")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelDERPHTTPClient)
|
||||
|
||||
nwait := 0
|
||||
startDial := func(dstPrimary, proto string) {
|
||||
|
@ -879,11 +879,13 @@ func (h *peerAPIHandler) handleServeSockStats(w http.ResponseWriter, r *http.Req
|
||||
fmt.Fprintln(w, "</thead>")
|
||||
|
||||
fmt.Fprintln(w, "<tbody>")
|
||||
labels := make([]string, 0, len(stats.Stats))
|
||||
labels := make([]sockstats.Label, 0, len(stats.Stats))
|
||||
for label := range stats.Stats {
|
||||
labels = append(labels, label)
|
||||
}
|
||||
sort.Strings(labels)
|
||||
slices.SortFunc(labels, func(a, b sockstats.Label) bool {
|
||||
return a.String() < b.String()
|
||||
})
|
||||
|
||||
txTotal := int64(0)
|
||||
rxTotal := int64(0)
|
||||
@ -893,7 +895,7 @@ func (h *peerAPIHandler) handleServeSockStats(w http.ResponseWriter, r *http.Req
|
||||
for _, label := range labels {
|
||||
stat := stats.Stats[label]
|
||||
fmt.Fprintln(w, "<tr>")
|
||||
fmt.Fprintf(w, "<td>%s</td>", html.EscapeString(label))
|
||||
fmt.Fprintf(w, "<td>%s</td>", html.EscapeString(label.String()))
|
||||
fmt.Fprintf(w, "<td align=right>%d</td>", stat.TxBytes)
|
||||
fmt.Fprintf(w, "<td align=right>%d</td>", stat.RxBytes)
|
||||
|
||||
|
@ -428,7 +428,7 @@ func (l *Logger) awaitInternetUp(ctx context.Context) {
|
||||
// origlen of -1 indicates that the body is not compressed.
|
||||
func (l *Logger) upload(ctx context.Context, body []byte, origlen int) (uploaded bool, err error) {
|
||||
const maxUploadTime = 45 * time.Second
|
||||
ctx = sockstats.WithSockStats(ctx, "logtail.Logger")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelLogtailLogger)
|
||||
ctx, cancel := context.WithTimeout(ctx, maxUploadTime)
|
||||
defer cancel()
|
||||
|
||||
|
@ -407,7 +407,7 @@ func (f *forwarder) getKnownDoHClientForProvider(urlBase string) (c *http.Client
|
||||
const dohType = "application/dns-message"
|
||||
|
||||
func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client, packet []byte) ([]byte, error) {
|
||||
ctx = sockstats.WithSockStats(ctx, "dns.forwarder:doh")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderDoH)
|
||||
metricDNSFwdDoH.Add(1)
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", urlBase, bytes.NewReader(packet))
|
||||
if err != nil {
|
||||
@ -487,7 +487,7 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn
|
||||
return nil, fmt.Errorf("unrecognized resolver type %q", rr.name.Addr)
|
||||
}
|
||||
metricDNSFwdUDP.Add(1)
|
||||
ctx = sockstats.WithSockStats(ctx, "dns.forwarder:udp")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderUDP)
|
||||
|
||||
ln, err := f.packetListener(ipp.Addr())
|
||||
if err != nil {
|
||||
|
@ -784,7 +784,7 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap) (_ *Report,
|
||||
ctx, cancel := context.WithTimeout(ctx, overallProbeTimeout)
|
||||
defer cancel()
|
||||
|
||||
ctx = sockstats.WithSockStats(ctx, "netcheck.Client")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelNetcheckClient)
|
||||
|
||||
if dm == nil {
|
||||
return nil, errors.New("netcheck: GetReport: DERP map is nil")
|
||||
|
@ -249,7 +249,7 @@ func (c *Client) upnpPort() uint16 {
|
||||
}
|
||||
|
||||
func (c *Client) listenPacket(ctx context.Context, network, addr string) (nettype.PacketConn, error) {
|
||||
ctx = sockstats.WithSockStats(ctx, "portmapper.Client")
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelPortmapperClient)
|
||||
|
||||
// When running under testing conditions, we bind the IGD server
|
||||
// to localhost, and may be running in an environment where our
|
||||
|
32
net/sockstats/label_string.go
Normal file
32
net/sockstats/label_string.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Code generated by "stringer -type Label -trimprefix Label"; DO NOT EDIT.
|
||||
|
||||
package sockstats
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LabelControlClientAuto-0]
|
||||
_ = x[LabelControlClientDialer-1]
|
||||
_ = x[LabelDERPHTTPClient-2]
|
||||
_ = x[LabelLogtailLogger-3]
|
||||
_ = x[LabelDNSForwarderDoH-4]
|
||||
_ = x[LabelDNSForwarderUDP-5]
|
||||
_ = x[LabelNetcheckClient-6]
|
||||
_ = x[LabelPortmapperClient-7]
|
||||
_ = x[LabelMagicsockConnUDP4-8]
|
||||
_ = x[LabelMagicsockConnUDP6-9]
|
||||
}
|
||||
|
||||
const _Label_name = "ControlClientAutoControlClientDialerDERPHTTPClientLogtailLoggerDNSForwarderDoHDNSForwarderUDPNetcheckClientPortmapperClientMagicsockConnUDP4MagicsockConnUDP6"
|
||||
|
||||
var _Label_index = [...]uint8{0, 17, 36, 50, 63, 78, 93, 107, 123, 140, 157}
|
||||
|
||||
func (i Label) String() string {
|
||||
if i >= Label(len(_Label_index)-1) {
|
||||
return "Label(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Label_name[_Label_index[i]:_Label_index[i+1]]
|
||||
}
|
@ -15,10 +15,32 @@
|
||||
)
|
||||
|
||||
type SockStats struct {
|
||||
Stats map[string]SockStat
|
||||
Stats map[Label]SockStat
|
||||
Interfaces []string
|
||||
}
|
||||
|
||||
// Label is an identifier for a socket that stats are collected for. A finite
|
||||
// set of values that may be used to label a socket to encourage grouping and
|
||||
// to make storage more efficient.
|
||||
type Label uint8
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type Label -trimprefix Label
|
||||
|
||||
// Labels are named after the package and function/struct that uses the socket.
|
||||
// Values may be persisted and thus existing entries should not be re-numbered.
|
||||
const (
|
||||
LabelControlClientAuto Label = 0 // control/controlclient/auto.go
|
||||
LabelControlClientDialer Label = 1 // control/controlhttp/client.go
|
||||
LabelDERPHTTPClient Label = 2 // derp/derphttp/derphttp_client.go
|
||||
LabelLogtailLogger Label = 3 // logtail/logtail.go
|
||||
LabelDNSForwarderDoH Label = 4 // net/dns/resolver/forwarder.go
|
||||
LabelDNSForwarderUDP Label = 5 // net/dns/resolver/forwarder.go
|
||||
LabelNetcheckClient Label = 6 // net/netcheck/netcheck.go
|
||||
LabelPortmapperClient Label = 7 // net/portmapper/portmapper.go
|
||||
LabelMagicsockConnUDP4 Label = 8 // wgengine/magicsock/magicsock.go
|
||||
LabelMagicsockConnUDP6 Label = 9 // wgengine/magicsock/magicsock.go
|
||||
)
|
||||
|
||||
type SockStat struct {
|
||||
TxBytes int64
|
||||
RxBytes int64
|
||||
@ -26,7 +48,7 @@ type SockStat struct {
|
||||
RxBytesByInterface map[string]int64
|
||||
}
|
||||
|
||||
func WithSockStats(ctx context.Context, label string) context.Context {
|
||||
func WithSockStats(ctx context.Context, label Label) context.Context {
|
||||
return withSockStats(ctx, label)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
"context"
|
||||
)
|
||||
|
||||
func withSockStats(ctx context.Context, label string) context.Context {
|
||||
func withSockStats(ctx context.Context, label Label) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ type sockStatCounters struct {
|
||||
// mu protects fields in this group. It should not be held in the per-read/
|
||||
// write callbacks.
|
||||
mu sync.Mutex
|
||||
countersByLabel map[string]*sockStatCounters
|
||||
countersByLabel map[Label]*sockStatCounters
|
||||
knownInterfaces map[int]string // interface index -> name
|
||||
usedInterfaces map[int]int // set of interface indexes
|
||||
|
||||
@ -32,12 +32,12 @@ type sockStatCounters struct {
|
||||
// write callbacks.
|
||||
currentInterface atomic.Uint32
|
||||
}{
|
||||
countersByLabel: make(map[string]*sockStatCounters),
|
||||
countersByLabel: make(map[Label]*sockStatCounters),
|
||||
knownInterfaces: make(map[int]string),
|
||||
usedInterfaces: make(map[int]int),
|
||||
}
|
||||
|
||||
func withSockStats(ctx context.Context, label string) context.Context {
|
||||
func withSockStats(ctx context.Context, label Label) context.Context {
|
||||
sockStats.mu.Lock()
|
||||
defer sockStats.mu.Unlock()
|
||||
counters, ok := sockStats.countersByLabel[label]
|
||||
@ -85,7 +85,7 @@ func get() *SockStats {
|
||||
defer sockStats.mu.Unlock()
|
||||
|
||||
r := &SockStats{
|
||||
Stats: make(map[string]SockStat),
|
||||
Stats: make(map[Label]SockStat),
|
||||
Interfaces: make([]string, 0, len(sockStats.usedInterfaces)),
|
||||
}
|
||||
for iface := range sockStats.usedInterfaces {
|
||||
|
@ -3050,7 +3050,12 @@ func (c *Conn) ReSTUN(why string) {
|
||||
// listenPacket opens a packet listener.
|
||||
// The network must be "udp4" or "udp6".
|
||||
func (c *Conn) listenPacket(network string, port uint16) (nettype.PacketConn, error) {
|
||||
ctx := sockstats.WithSockStats(context.Background(), fmt.Sprintf("magicsock.Conn:%s", network)) // unused without DNS name to resolve
|
||||
ctx := context.Background() // unused without DNS name to resolve
|
||||
if network == "udp4" {
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelMagicsockConnUDP4)
|
||||
} else {
|
||||
ctx = sockstats.WithSockStats(ctx, sockstats.LabelMagicsockConnUDP6)
|
||||
}
|
||||
addr := net.JoinHostPort("", fmt.Sprint(port))
|
||||
if c.testOnlyPacketListener != nil {
|
||||
return nettype.MakePacketListenerWithNetIP(c.testOnlyPacketListener).ListenPacket(ctx, network, addr)
|
||||
|
Loading…
Reference in New Issue
Block a user