net/udprelay: expose peer relay metrics (#18218)
Adding both user and client metrics for peer relay forwarded bytes and
packets, and the total endpoints gauge.
User metrics:
tailscaled_peer_relay_forwarded_packets_total{transport_in, transport_out}
tailscaled_peer_relay_forwarded_bytes_total{transport_in, transport_out}
tailscaled_peer_relay_endpoints_total{}
Where the transport labels can be of "udp4" or "udp6".
Client metrics:
udprelay_forwarded_(packets|bytes)_udp(4|6)_udp(4|6)
udprelay_endpoints
RELNOTE: Expose tailscaled metrics for peer relay.
Updates tailscale/corp#30820
Change-Id: I1a905d15bdc5ee84e28017e0b93210e2d9660259
Signed-off-by: Alex Valiushko <alexvaliushko@tailscale.com>
main
parent
bb3529fcd4
commit
c40f352103
@ -0,0 +1,153 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package udprelay |
||||
|
||||
import ( |
||||
"expvar" |
||||
|
||||
"tailscale.com/util/clientmetric" |
||||
"tailscale.com/util/usermetric" |
||||
) |
||||
|
||||
var ( |
||||
// Although we only need one, [clientmetric.AggregateCounter] is the only
|
||||
// method to embed [expvar.Int] into client metrics.
|
||||
cMetricForwarded44Packets = clientmetric.NewAggregateCounter("udprelay_forwarded_packets_udp4_udp4") |
||||
cMetricForwarded46Packets = clientmetric.NewAggregateCounter("udprelay_forwarded_packets_udp4_udp6") |
||||
cMetricForwarded64Packets = clientmetric.NewAggregateCounter("udprelay_forwarded_packets_udp6_udp4") |
||||
cMetricForwarded66Packets = clientmetric.NewAggregateCounter("udprelay_forwarded_packets_udp6_udp6") |
||||
|
||||
cMetricForwarded44Bytes = clientmetric.NewAggregateCounter("udprelay_forwarded_bytes_udp4_udp4") |
||||
cMetricForwarded46Bytes = clientmetric.NewAggregateCounter("udprelay_forwarded_bytes_udp4_udp6") |
||||
cMetricForwarded64Bytes = clientmetric.NewAggregateCounter("udprelay_forwarded_bytes_udp6_udp4") |
||||
cMetricForwarded66Bytes = clientmetric.NewAggregateCounter("udprelay_forwarded_bytes_udp6_udp6") |
||||
|
||||
// [clientmetric.Gauge] does not let us embed existing counters,
|
||||
// [metrics.addEndpoints] records data into client and user gauges independently.
|
||||
cMetricEndpoints = clientmetric.NewGauge("udprelay_endpoints") |
||||
) |
||||
|
||||
type transport string |
||||
|
||||
const ( |
||||
transportUDP4 transport = "udp4" |
||||
transportUDP6 transport = "udp6" |
||||
) |
||||
|
||||
type forwardedLabel struct { |
||||
transportIn transport `prom:"transport_in"` |
||||
transportOut transport `prom:"transport_out"` |
||||
} |
||||
|
||||
type endpointLabel struct { |
||||
} |
||||
|
||||
type metrics struct { |
||||
forwarded44Packets expvar.Int |
||||
forwarded46Packets expvar.Int |
||||
forwarded64Packets expvar.Int |
||||
forwarded66Packets expvar.Int |
||||
|
||||
forwarded44Bytes expvar.Int |
||||
forwarded46Bytes expvar.Int |
||||
forwarded64Bytes expvar.Int |
||||
forwarded66Bytes expvar.Int |
||||
|
||||
endpoints expvar.Int |
||||
} |
||||
|
||||
// registerMetrics publishes user and client metric counters for peer relay server.
|
||||
//
|
||||
// It will panic if called twice with the same registry.
|
||||
func registerMetrics(reg *usermetric.Registry) *metrics { |
||||
var ( |
||||
uMetricForwardedPackets = usermetric.NewMultiLabelMapWithRegistry[forwardedLabel]( |
||||
reg, |
||||
"tailscaled_peer_relay_forwarded_packets_total", |
||||
"counter", |
||||
"Number of packets forwarded via Peer Relay", |
||||
) |
||||
uMetricForwardedBytes = usermetric.NewMultiLabelMapWithRegistry[forwardedLabel]( |
||||
reg, |
||||
"tailscaled_peer_relay_forwarded_bytes_total", |
||||
"counter", |
||||
"Number of bytes forwarded via Peer Relay", |
||||
) |
||||
uMetricEndpoints = usermetric.NewMultiLabelMapWithRegistry[endpointLabel]( |
||||
reg, |
||||
"tailscaled_peer_relay_endpoints_total", |
||||
"gauge", |
||||
"Number of allocated Peer Relay endpoints", |
||||
) |
||||
forwarded44 = forwardedLabel{transportIn: transportUDP4, transportOut: transportUDP4} |
||||
forwarded46 = forwardedLabel{transportIn: transportUDP4, transportOut: transportUDP6} |
||||
forwarded64 = forwardedLabel{transportIn: transportUDP6, transportOut: transportUDP4} |
||||
forwarded66 = forwardedLabel{transportIn: transportUDP6, transportOut: transportUDP6} |
||||
m = new(metrics) |
||||
) |
||||
|
||||
// Publish user metrics.
|
||||
uMetricForwardedPackets.Set(forwarded44, &m.forwarded44Packets) |
||||
uMetricForwardedPackets.Set(forwarded46, &m.forwarded46Packets) |
||||
uMetricForwardedPackets.Set(forwarded64, &m.forwarded64Packets) |
||||
uMetricForwardedPackets.Set(forwarded66, &m.forwarded66Packets) |
||||
|
||||
uMetricForwardedBytes.Set(forwarded44, &m.forwarded44Bytes) |
||||
uMetricForwardedBytes.Set(forwarded46, &m.forwarded46Bytes) |
||||
uMetricForwardedBytes.Set(forwarded64, &m.forwarded64Bytes) |
||||
uMetricForwardedBytes.Set(forwarded66, &m.forwarded66Bytes) |
||||
|
||||
uMetricEndpoints.Set(endpointLabel{}, &m.endpoints) |
||||
|
||||
// Publish client metrics.
|
||||
cMetricForwarded44Packets.Register(&m.forwarded44Packets) |
||||
cMetricForwarded46Packets.Register(&m.forwarded46Packets) |
||||
cMetricForwarded64Packets.Register(&m.forwarded64Packets) |
||||
cMetricForwarded66Packets.Register(&m.forwarded66Packets) |
||||
cMetricForwarded44Bytes.Register(&m.forwarded44Bytes) |
||||
cMetricForwarded46Bytes.Register(&m.forwarded46Bytes) |
||||
cMetricForwarded64Bytes.Register(&m.forwarded64Bytes) |
||||
cMetricForwarded66Bytes.Register(&m.forwarded66Bytes) |
||||
|
||||
return m |
||||
} |
||||
|
||||
// addEndpoints updates the total endpoints gauge. Value can be negative.
|
||||
// It records two gauges independently, see [cMetricEndpoints] doc.
|
||||
func (m *metrics) addEndpoints(value int64) { |
||||
m.endpoints.Add(value) |
||||
cMetricEndpoints.Add(value) |
||||
} |
||||
|
||||
// countForwarded records user and client metrics according to the
|
||||
// inbound and outbound address families.
|
||||
func (m *metrics) countForwarded(in4, out4 bool, bytes, packets int64) { |
||||
if in4 && out4 { |
||||
m.forwarded44Packets.Add(packets) |
||||
m.forwarded44Bytes.Add(bytes) |
||||
} else if in4 && !out4 { |
||||
m.forwarded46Packets.Add(packets) |
||||
m.forwarded46Bytes.Add(bytes) |
||||
} else if !in4 && out4 { |
||||
m.forwarded64Packets.Add(packets) |
||||
m.forwarded64Bytes.Add(bytes) |
||||
} else { |
||||
m.forwarded66Packets.Add(packets) |
||||
m.forwarded66Bytes.Add(bytes) |
||||
} |
||||
} |
||||
|
||||
// deregisterMetrics unregisters the underlying expvar counters
|
||||
// from clientmetrics.
|
||||
func deregisterMetrics() { |
||||
cMetricForwarded44Packets.UnregisterAll() |
||||
cMetricForwarded46Packets.UnregisterAll() |
||||
cMetricForwarded64Packets.UnregisterAll() |
||||
cMetricForwarded66Packets.UnregisterAll() |
||||
cMetricForwarded44Bytes.UnregisterAll() |
||||
cMetricForwarded46Bytes.UnregisterAll() |
||||
cMetricForwarded64Bytes.UnregisterAll() |
||||
cMetricForwarded66Bytes.UnregisterAll() |
||||
cMetricEndpoints.Set(0) |
||||
} |
||||
@ -0,0 +1,63 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package udprelay |
||||
|
||||
import ( |
||||
"slices" |
||||
"testing" |
||||
|
||||
qt "github.com/frankban/quicktest" |
||||
"tailscale.com/util/usermetric" |
||||
) |
||||
|
||||
func TestMetrics(t *testing.T) { |
||||
c := qt.New(t) |
||||
deregisterMetrics() |
||||
r := &usermetric.Registry{} |
||||
m := registerMetrics(r) |
||||
|
||||
// Expect certain prom names registered.
|
||||
have := r.MetricNames() |
||||
want := []string{ |
||||
"tailscaled_peer_relay_forwarded_packets_total", |
||||
"tailscaled_peer_relay_forwarded_bytes_total", |
||||
"tailscaled_peer_relay_endpoints_total", |
||||
} |
||||
slices.Sort(have) |
||||
slices.Sort(want) |
||||
c.Assert(have, qt.CmpEquals(), want) |
||||
|
||||
// Validate addEndpoints.
|
||||
m.addEndpoints(1) |
||||
c.Assert(m.endpoints.Value(), qt.Equals, int64(1)) |
||||
c.Assert(cMetricEndpoints.Value(), qt.Equals, int64(1)) |
||||
m.addEndpoints(-1) |
||||
c.Assert(m.endpoints.Value(), qt.Equals, int64(0)) |
||||
c.Assert(cMetricEndpoints.Value(), qt.Equals, int64(0)) |
||||
|
||||
// Validate countForwarded.
|
||||
m.countForwarded(true, true, 1, 1) |
||||
c.Assert(m.forwarded44Bytes.Value(), qt.Equals, int64(1)) |
||||
c.Assert(m.forwarded44Packets.Value(), qt.Equals, int64(1)) |
||||
c.Assert(cMetricForwarded44Bytes.Value(), qt.Equals, int64(1)) |
||||
c.Assert(cMetricForwarded44Packets.Value(), qt.Equals, int64(1)) |
||||
|
||||
m.countForwarded(true, false, 2, 2) |
||||
c.Assert(m.forwarded46Bytes.Value(), qt.Equals, int64(2)) |
||||
c.Assert(m.forwarded46Packets.Value(), qt.Equals, int64(2)) |
||||
c.Assert(cMetricForwarded46Bytes.Value(), qt.Equals, int64(2)) |
||||
c.Assert(cMetricForwarded46Packets.Value(), qt.Equals, int64(2)) |
||||
|
||||
m.countForwarded(false, true, 3, 3) |
||||
c.Assert(m.forwarded64Bytes.Value(), qt.Equals, int64(3)) |
||||
c.Assert(m.forwarded64Packets.Value(), qt.Equals, int64(3)) |
||||
c.Assert(cMetricForwarded64Bytes.Value(), qt.Equals, int64(3)) |
||||
c.Assert(cMetricForwarded64Packets.Value(), qt.Equals, int64(3)) |
||||
|
||||
m.countForwarded(false, false, 4, 4) |
||||
c.Assert(m.forwarded66Bytes.Value(), qt.Equals, int64(4)) |
||||
c.Assert(m.forwarded66Packets.Value(), qt.Equals, int64(4)) |
||||
c.Assert(cMetricForwarded66Bytes.Value(), qt.Equals, int64(4)) |
||||
c.Assert(cMetricForwarded66Packets.Value(), qt.Equals, int64(4)) |
||||
} |
||||
Loading…
Reference in new issue