diff --git a/util/clientmetric/clientmetric.go b/util/clientmetric/clientmetric.go index b2d356b60..56a39cd1f 100644 --- a/util/clientmetric/clientmetric.go +++ b/util/clientmetric/clientmetric.go @@ -9,6 +9,7 @@ import ( "bytes" "encoding/binary" "encoding/hex" + "expvar" "fmt" "io" "sort" @@ -223,6 +224,33 @@ func NewGaugeFunc(name string, f func() int64) *Metric { return m } +type AggregateCounter struct { + mu sync.RWMutex + counters []*expvar.Int +} + +func (c *AggregateCounter) Value() int64 { + c.mu.RLock() + defer c.mu.RUnlock() + var sum int64 + for _, c := range c.counters { + sum += c.Value() + } + return sum +} + +func (c *AggregateCounter) Add(counter *expvar.Int) { + c.mu.Lock() + defer c.mu.Unlock() + c.counters = append(c.counters, counter) +} + +func NewAggregateCounter(name string) *AggregateCounter { + c := &AggregateCounter{} + NewGaugeFunc(name, c.Value) + return c +} + // WritePrometheusExpositionFormat writes all client metrics to w in // the Prometheus text-based exposition format. // diff --git a/wgengine/magicsock/derp.go b/wgengine/magicsock/derp.go index 913a1f447..73cccc707 100644 --- a/wgengine/magicsock/derp.go +++ b/wgengine/magicsock/derp.go @@ -690,7 +690,6 @@ func (c *connBind) receiveDERP(buffs [][]byte, sizes []int, eps []conn.Endpoint) // No data read occurred. Wait for another packet. continue } - metricRecvDataPacketsDERP.Add(1) c.metrics.inboundPacketsDERPTotal.Add(1) c.metrics.inboundBytesDERPTotal.Add(int64(n)) sizes[0] = n diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index 48ecfeecd..ffa572b1f 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -623,6 +623,10 @@ func registerMetrics(reg *usermetric.Registry) *metrics { outboundBytesDERPTotal: &expvar.Int{}, } + metricRecvDataPacketsDERP.Add(m.inboundPacketsDERPTotal) + metricSendUDP.Add(m.outboundPacketsIPv4Total) + metricSendUDP.Add(m.outboundPacketsIPv6Total) + inboundPacketsTotal.Set(pathDirectV4, m.inboundPacketsIPv4Total) inboundPacketsTotal.Set(pathDirectV6, m.inboundPacketsIPv6Total) inboundPacketsTotal.Set(pathDERP, m.inboundPacketsDERPTotal) @@ -1262,8 +1266,6 @@ func (c *Conn) sendUDP(ipp netip.AddrPort, b []byte) (sent bool, err error) { _ = c.maybeRebindOnError(runtime.GOOS, err) } else { if sent { - metricSendUDP.Add(1) - switch { case ipp.Addr().Is4(): c.metrics.outboundPacketsIPv4Total.Add(1) @@ -3075,7 +3077,7 @@ var ( metricSendDERPErrorChan = clientmetric.NewCounter("magicsock_send_derp_error_chan") metricSendDERPErrorClosed = clientmetric.NewCounter("magicsock_send_derp_error_closed") metricSendDERPErrorQueue = clientmetric.NewCounter("magicsock_send_derp_error_queue") - metricSendUDP = clientmetric.NewCounter("magicsock_send_udp") + metricSendUDP = clientmetric.NewAggregateCounter("magicsock_send_udp") metricSendUDPError = clientmetric.NewCounter("magicsock_send_udp_error") metricSendDERP = clientmetric.NewCounter("magicsock_send_derp") metricSendDERPError = clientmetric.NewCounter("magicsock_send_derp_error") @@ -3083,7 +3085,7 @@ var ( // Data packets (non-disco) metricSendData = clientmetric.NewCounter("magicsock_send_data") metricSendDataNetworkDown = clientmetric.NewCounter("magicsock_send_data_network_down") - metricRecvDataPacketsDERP = clientmetric.NewCounter("magicsock_recv_data_derp") + metricRecvDataPacketsDERP = clientmetric.NewAggregateCounter("magicsock_recv_data_derp") metricRecvDataPacketsIPv4 = clientmetric.NewCounter("magicsock_recv_data_ipv4") metricRecvDataPacketsIPv6 = clientmetric.NewCounter("magicsock_recv_data_ipv6") diff --git a/wgengine/magicsock/magicsock_test.go b/wgengine/magicsock/magicsock_test.go index 62b27f75a..dae27c8f3 100644 --- a/wgengine/magicsock/magicsock_test.go +++ b/wgengine/magicsock/magicsock_test.go @@ -1264,6 +1264,8 @@ func assertConnStatsAndUserMetricsEqual(t *testing.T, ms *magicStack) { assertEqual(t, "derp packets outbound", physDERPTxPackets, metricDERPTxPackets) assertEqual(t, "ipv4 packets inbound", physIPv4RxPackets, metricIPv4RxPackets) assertEqual(t, "ipv4 packets outbound", physIPv4TxPackets, metricIPv4TxPackets) + + assertEqual(t, "outbound udp packets - compare with clientmetric", metricSendUDP.Value(), metricIPv4TxPackets*2) } func assertEqual(t *testing.T, name string, a, b any) {