Change-Id: I5ff861f12cc1a0b00e2cd2289d6f51fd936b0e0a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
bradfitz/rm_usermetrics_66KB
Brad Fitzpatrick 2 months ago
parent 34242df51b
commit 59e5b81832

@ -20,7 +20,6 @@ import (
"time" "time"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/metrics"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstime" "tailscale.com/tstime"
"tailscale.com/types/opt" "tailscale.com/types/opt"
@ -133,7 +132,7 @@ type Tracker struct {
lastLoginErr error lastLoginErr error
localLogConfigErr error localLogConfigErr error
tlsConnectionErrors map[string]error // map[ServerName]error tlsConnectionErrors map[string]error // map[ServerName]error
metricHealthMessage *metrics.MultiLabelMap[metricHealthMessageLabel] metricHealthMessage *usermetric.MultiLabelMap[metricHealthMessageLabel]
} }
// NewTracker contructs a new [Tracker] and attaches the given eventbus. // NewTracker contructs a new [Tracker] and attaches the given eventbus.

@ -25,7 +25,6 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/stack"
"tailscale.com/disco" "tailscale.com/disco"
"tailscale.com/feature/buildfeatures" "tailscale.com/feature/buildfeatures"
tsmetrics "tailscale.com/metrics"
"tailscale.com/net/connstats" "tailscale.com/net/connstats"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/packet/checksum" "tailscale.com/net/packet/checksum"
@ -214,8 +213,8 @@ type Wrapper struct {
} }
type metrics struct { type metrics struct {
inboundDroppedPacketsTotal *tsmetrics.MultiLabelMap[usermetric.DropLabels] inboundDroppedPacketsTotal *usermetric.MultiLabelMap[usermetric.DropLabels]
outboundDroppedPacketsTotal *tsmetrics.MultiLabelMap[usermetric.DropLabels] outboundDroppedPacketsTotal *usermetric.MultiLabelMap[usermetric.DropLabels]
} }
func registerMetrics(reg *usermetric.Registry) *metrics { func registerMetrics(reg *usermetric.Registry) *metrics {

@ -9,16 +9,11 @@ package usermetric
import ( import (
"sync" "sync"
"tailscale.com/metrics"
) )
// Metrics contains user-facing metrics that are used by multiple packages. // Metrics contains user-facing metrics that are used by multiple packages.
type Metrics struct { type Metrics struct {
initOnce sync.Once initOnce sync.Once
droppedPacketsInbound *metrics.MultiLabelMap[DropLabels]
droppedPacketsOutbound *metrics.MultiLabelMap[DropLabels]
} }
// DropReason is the reason why a packet was dropped. // DropReason is the reason why a packet was dropped.
@ -53,33 +48,13 @@ type DropLabels struct {
Reason DropReason Reason DropReason
} }
// initOnce initializes the common metrics.
func (r *Registry) initOnce() {
r.m.initOnce.Do(func() {
r.m.droppedPacketsInbound = NewMultiLabelMapWithRegistry[DropLabels](
r,
"tailscaled_inbound_dropped_packets_total",
"counter",
"Counts the number of dropped packets received by the node from other peers",
)
r.m.droppedPacketsOutbound = NewMultiLabelMapWithRegistry[DropLabels](
r,
"tailscaled_outbound_dropped_packets_total",
"counter",
"Counts the number of packets dropped while being sent to other peers",
)
})
}
// DroppedPacketsOutbound returns the outbound dropped packet metric, creating it // DroppedPacketsOutbound returns the outbound dropped packet metric, creating it
// if necessary. // if necessary.
func (r *Registry) DroppedPacketsOutbound() *metrics.MultiLabelMap[DropLabels] { func (r *Registry) DroppedPacketsOutbound() *MultiLabelMap[DropLabels] {
r.initOnce() return &MultiLabelMap[DropLabels]{}
return r.m.droppedPacketsOutbound
} }
// DroppedPacketsInbound returns the inbound dropped packet metric. // DroppedPacketsInbound returns the inbound dropped packet metric.
func (r *Registry) DroppedPacketsInbound() *metrics.MultiLabelMap[DropLabels] { func (r *Registry) DroppedPacketsInbound() *MultiLabelMap[DropLabels] {
r.initOnce() return &MultiLabelMap[DropLabels]{}
return r.m.droppedPacketsInbound
} }

@ -6,24 +6,19 @@
package usermetric package usermetric
import ( import (
"expvar"
"fmt"
"io" "io"
"net/http" "net/http"
"strings"
"tailscale.com/metrics"
"tailscale.com/tsweb/varz"
"tailscale.com/util/set"
) )
// Registry tracks user-facing metrics of various Tailscale subsystems. // Registry tracks user-facing metrics of various Tailscale subsystems.
type Registry struct { type Registry struct{}
vars expvar.Map
// m contains common metrics owned by the registry. type noop struct{}
m Metrics
} type MultiLabelMap[T comparable] struct{}
func (*MultiLabelMap[T]) Add(T, int64) {}
func (*MultiLabelMap[T]) Set(T, any) {}
// NewMultiLabelMapWithRegistry creates and register a new // NewMultiLabelMapWithRegistry creates and register a new
// MultiLabelMap[T] variable with the given name and returns it. // MultiLabelMap[T] variable with the given name and returns it.
@ -32,88 +27,37 @@ type Registry struct {
// Note that usermetric are not protected against duplicate // Note that usermetric are not protected against duplicate
// metrics name. It is the caller's responsibility to ensure that // metrics name. It is the caller's responsibility to ensure that
// the name is unique. // the name is unique.
func NewMultiLabelMapWithRegistry[T comparable](m *Registry, name string, promType, helpText string) *metrics.MultiLabelMap[T] { func NewMultiLabelMapWithRegistry[T comparable](m *Registry, name string, promType, helpText string) *MultiLabelMap[T] {
ml := &metrics.MultiLabelMap[T]{ return &MultiLabelMap[T]{}
Type: promType,
Help: helpText,
}
var zero T
_ = metrics.LabelString(zero) // panic early if T is invalid
m.vars.Set(name, ml)
return ml
} }
// Gauge is a gauge metric with no labels. // Gauge is a gauge metric with no labels.
type Gauge struct { type Gauge struct{}
m *expvar.Float
help string var noopGauge = &Gauge{}
}
// NewGauge creates and register a new gauge metric with the given name and help text. // NewGauge creates and register a new gauge metric with the given name and help text.
func (r *Registry) NewGauge(name, help string) *Gauge { func (r *Registry) NewGauge(name, help string) *Gauge { return noopGauge }
g := &Gauge{&expvar.Float{}, help}
r.vars.Set(name, g)
return g
}
// Set sets the gauge to the given value. func (g *Gauge) Add(v float64) {}
func (g *Gauge) Set(v float64) { func (g *Gauge) Set(v float64) {}
if g == nil {
return
}
g.m.Set(v)
}
// String returns the string of the underlying expvar.Float. // Set sets the gauge to the given value.
// This satisfies the expvar.Var interface. func (noop) Set(v float64) {}
func (g *Gauge) String() string {
if g == nil {
return ""
}
return g.m.String()
}
// WritePrometheus writes the gauge metric in Prometheus format to the given writer. // WritePrometheus writes the gauge metric in Prometheus format to the given writer.
// This satisfies the varz.PrometheusWriter interface. // This satisfies the varz.PrometheusWriter interface.
func (g *Gauge) WritePrometheus(w io.Writer, name string) { func (g *Gauge) WritePrometheus(w io.Writer, name string) {
io.WriteString(w, "# TYPE ") panic("")
io.WriteString(w, name)
io.WriteString(w, " gauge\n")
if g.help != "" {
io.WriteString(w, "# HELP ")
io.WriteString(w, name)
io.WriteString(w, " ")
io.WriteString(w, g.help)
io.WriteString(w, "\n")
}
io.WriteString(w, name)
fmt.Fprintf(w, " %v\n", g.m.Value())
} }
// Handler returns a varz.Handler that serves the userfacing expvar contained // Handler returns a varz.Handler that serves the userfacing expvar contained
// in this package. // in this package.
func (r *Registry) Handler(w http.ResponseWriter, req *http.Request) { func (r *Registry) Handler(w http.ResponseWriter, req *http.Request) {
varz.ExpvarDoHandler(r.vars.Do)(w, req) http.NotFound(w, req)
}
// String returns the string representation of all the metrics and their
// values in the registry. It is useful for debugging.
func (r *Registry) String() string {
var sb strings.Builder
r.vars.Do(func(kv expvar.KeyValue) {
fmt.Fprintf(&sb, "%s: %v\n", kv.Key, kv.Value)
})
return sb.String()
} }
// Metrics returns the name of all the metrics in the registry. // Metrics returns the name of all the metrics in the registry.
func (r *Registry) MetricNames() []string { func (r *Registry) MetricNames() []string {
ret := make(set.Set[string]) return nil
r.vars.Do(func(kv expvar.KeyValue) {
ret.Add(kv.Key)
})
return ret.Slice()
} }

Loading…
Cancel
Save