feature/featuretags: make usermetrics modular

Saves ~102 KB from the min build.

Updates #12614

Change-Id: Ie1d4f439321267b9f98046593cb289ee3c4d6249
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-10-06 12:02:16 -07:00
committed by Brad Fitzpatrick
parent ea8e991d69
commit d816454a88
17 changed files with 97 additions and 31 deletions

View File

@@ -742,7 +742,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
tailscale.com/logtail from tailscale.com/control/controlclient+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/metrics from tailscale.com/tsweb+
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+

View File

@@ -28,7 +28,9 @@ import (
"tailscale.com/ipn"
"tailscale.com/net/netmon"
"tailscale.com/tailcfg"
"tailscale.com/tsweb/varz"
"tailscale.com/types/key"
"tailscale.com/util/clientmetric"
"tailscale.com/util/eventbus"
)
@@ -58,6 +60,12 @@ func newDebugMux() *http.ServeMux {
return mux
}
func servePrometheusMetrics(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
varz.Handler(w, r)
clientmetric.WritePrometheusExpositionFormat(w)
}
func debugMode(args []string) error {
fs := flag.NewFlagSet("debug", flag.ExitOnError)
fs.BoolVar(&debugArgs.ifconfig, "ifconfig", false, "If true, print network interface state")

View File

@@ -76,7 +76,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
tailscale.com/net/connstats from tailscale.com/net/tstun+
@@ -123,7 +122,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/tstime from tailscale.com/control/controlclient+
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
tailscale.com/types/dnstype from tailscale.com/client/tailscale/apitype+
tailscale.com/types/empty from tailscale.com/ipn+
@@ -150,7 +148,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/cloudenv from tailscale.com/hostinfo+
tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/util/dirwalk from tailscale.com/metrics
tailscale.com/util/dnsname from tailscale.com/appc+
tailscale.com/util/eventbus from tailscale.com/control/controlclient+
tailscale.com/util/execqueue from tailscale.com/appc+
@@ -205,7 +202,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
golang.org/x/crypto/nacl/secretbox from golang.org/x/crypto/nacl/box
golang.org/x/crypto/poly1305 from github.com/tailscale/wireguard-go/device
golang.org/x/crypto/salsa20/salsa from golang.org/x/crypto/nacl/box+
golang.org/x/exp/constraints from tailscale.com/tsweb/varz+
golang.org/x/exp/constraints from tailscale.com/util/set
golang.org/x/exp/maps from tailscale.com/ipn/store/mem
golang.org/x/net/bpf from github.com/mdlayher/genetlink+
golang.org/x/net/dns/dnsmessage from tailscale.com/ipn/ipnlocal+
@@ -321,7 +318,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
encoding/json from expvar+
encoding/pem from crypto/tls+
errors from bufio+
expvar from tailscale.com/metrics+
expvar from tailscale.com/wgengine/magicsock
flag from tailscale.com/cmd/tailscaled+
fmt from compress/flate+
hash from crypto+

View File

@@ -99,7 +99,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/net/ace from tailscale.com/cmd/tailscale/cli
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
@@ -149,7 +148,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/tstime from tailscale.com/control/controlclient+
tailscale.com/tstime/mono from tailscale.com/net/tstun+
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
tailscale.com/tsweb/varz from tailscale.com/cmd/tailscaled+
tailscale.com/types/appctype from tailscale.com/ipn/ipnlocal+
tailscale.com/types/dnstype from tailscale.com/client/tailscale/apitype+
tailscale.com/types/empty from tailscale.com/ipn+
@@ -177,7 +175,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/cmpver from tailscale.com/clientupdate
tailscale.com/util/ctxkey from tailscale.com/client/tailscale/apitype+
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/util/dirwalk from tailscale.com/metrics
tailscale.com/util/dnsname from tailscale.com/appc+
tailscale.com/util/eventbus from tailscale.com/client/local+
tailscale.com/util/execqueue from tailscale.com/appc+
@@ -233,7 +230,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
golang.org/x/crypto/nacl/secretbox from golang.org/x/crypto/nacl/box
golang.org/x/crypto/poly1305 from github.com/tailscale/wireguard-go/device
golang.org/x/crypto/salsa20/salsa from golang.org/x/crypto/nacl/box+
golang.org/x/exp/constraints from tailscale.com/tsweb/varz+
golang.org/x/exp/constraints from tailscale.com/util/set
golang.org/x/exp/maps from tailscale.com/ipn/store/mem
golang.org/x/net/bpf from github.com/mdlayher/genetlink+
golang.org/x/net/dns/dnsmessage from tailscale.com/cmd/tailscale/cli+
@@ -351,7 +348,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
encoding/json from expvar+
encoding/pem from crypto/tls+
errors from bufio+
expvar from tailscale.com/metrics+
expvar from tailscale.com/wgengine/magicsock
flag from tailscale.com/cmd/tailscaled+
fmt from compress/flate+
hash from crypto+

View File

@@ -323,7 +323,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/logpolicy from tailscale.com/cmd/tailscaled+
tailscale.com/logtail from tailscale.com/cmd/tailscaled+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/metrics from tailscale.com/tsweb+
tailscale.com/net/ace from tailscale.com/feature/ace
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock+

View File

@@ -265,6 +265,9 @@ func TestMinTailscaledWithCLI(t *testing.T) {
"hujson",
"pprof",
"multierr", // https://github.com/tailscale/tailscale/pull/17379
"tailscale.com/metrics",
"tailscale.com/tsweb/varz",
"dirwalk",
}
deptest.DepChecker{
GOOS: "linux",

View File

@@ -51,11 +51,9 @@ import (
"tailscale.com/safesocket"
"tailscale.com/syncs"
"tailscale.com/tsd"
"tailscale.com/tsweb/varz"
"tailscale.com/types/flagtype"
"tailscale.com/types/logger"
"tailscale.com/types/logid"
"tailscale.com/util/clientmetric"
"tailscale.com/util/osshare"
"tailscale.com/util/syspolicy/pkey"
"tailscale.com/util/syspolicy/policyclient"
@@ -831,12 +829,6 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
var hookNewDebugMux feature.Hook[func() *http.ServeMux]
func servePrometheusMetrics(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
varz.Handler(w, r)
clientmetric.WritePrometheusExpositionFormat(w)
}
func runDebugServer(logf logger.Logf, mux *http.ServeMux, addr string) {
if !buildfeatures.HasDebug {
return

View File

@@ -170,7 +170,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
tailscale.com/logtail from tailscale.com/control/controlclient+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/metrics from tailscale.com/tsweb+
tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+

View File

@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build ts_omit_usermetrics
package buildfeatures
// HasUserMetrics is whether the binary was built with support for modular feature "Usermetrics (documented, stable) metrics support".
// Specifically, it's whether the binary was NOT built with the "ts_omit_usermetrics" build tag.
// It's a const so it can be used for dead code elimination.
const HasUserMetrics = false

View File

@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build !ts_omit_usermetrics
package buildfeatures
// HasUserMetrics is whether the binary was built with support for modular feature "Usermetrics (documented, stable) metrics support".
// Specifically, it's whether the binary was NOT built with the "ts_omit_usermetrics" build tag.
// It's a const so it can be used for dead code elimination.
const HasUserMetrics = true

View File

@@ -270,6 +270,10 @@ var Features = map[FeatureTag]FeatureMeta{
Sym: "UseProxy",
Desc: "Support using system proxies as specified by env vars or the system configuration to reach Tailscale servers.",
},
"usermetrics": {
Sym: "UserMetrics",
Desc: "Usermetrics (documented, stable) metrics support",
},
"wakeonlan": {Sym: "WakeOnLAN", Desc: "Wake-on-LAN support"},
"webclient": {
Sym: "WebClient", Desc: "Web client support",

View File

@@ -99,7 +99,6 @@ var handler = map[string]LocalAPIHandler{
"status": (*Handler).serveStatus,
"update/check": (*Handler).serveUpdateCheck,
"upload-client-metrics": (*Handler).serveUploadClientMetrics,
"usermetrics": (*Handler).serveUserMetrics,
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
"whois": (*Handler).serveWhoIs,
}
@@ -126,6 +125,9 @@ func init() {
Register("dns-osconfig", (*Handler).serveDNSOSConfig)
Register("dns-query", (*Handler).serveDNSQuery)
}
if buildfeatures.HasUserMetrics {
Register("usermetrics", (*Handler).serveUserMetrics)
}
}
// Register registers a new LocalAPI handler for the given name.

View File

@@ -24,7 +24,6 @@ import (
"go4.org/mem"
"tailscale.com/disco"
"tailscale.com/feature/buildfeatures"
tsmetrics "tailscale.com/metrics"
"tailscale.com/net/connstats"
"tailscale.com/net/packet"
"tailscale.com/net/packet/checksum"
@@ -213,8 +212,8 @@ type Wrapper struct {
}
type metrics struct {
inboundDroppedPacketsTotal *tsmetrics.MultiLabelMap[usermetric.DropLabels]
outboundDroppedPacketsTotal *tsmetrics.MultiLabelMap[usermetric.DropLabels]
inboundDroppedPacketsTotal *usermetric.MultiLabelMap[usermetric.DropLabels]
outboundDroppedPacketsTotal *usermetric.MultiLabelMap[usermetric.DropLabels]
}
func registerMetrics(reg *usermetric.Registry) *metrics {

View File

@@ -166,7 +166,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
tailscale.com/logpolicy from tailscale.com/ipn/ipnlocal+
tailscale.com/logtail from tailscale.com/control/controlclient+
tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+
tailscale.com/metrics from tailscale.com/net/tstun+
tailscale.com/metrics from tailscale.com/tsweb+
tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+
💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock
tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+

View File

@@ -10,15 +10,15 @@ package usermetric
import (
"sync"
"tailscale.com/metrics"
"tailscale.com/feature/buildfeatures"
)
// Metrics contains user-facing metrics that are used by multiple packages.
type Metrics struct {
initOnce sync.Once
droppedPacketsInbound *metrics.MultiLabelMap[DropLabels]
droppedPacketsOutbound *metrics.MultiLabelMap[DropLabels]
droppedPacketsInbound *MultiLabelMap[DropLabels]
droppedPacketsOutbound *MultiLabelMap[DropLabels]
}
// DropReason is the reason why a packet was dropped.
@@ -55,6 +55,9 @@ type DropLabels struct {
// initOnce initializes the common metrics.
func (r *Registry) initOnce() {
if !buildfeatures.HasUserMetrics {
return
}
r.m.initOnce.Do(func() {
r.m.droppedPacketsInbound = NewMultiLabelMapWithRegistry[DropLabels](
r,
@@ -73,13 +76,13 @@ func (r *Registry) initOnce() {
// DroppedPacketsOutbound returns the outbound dropped packet metric, creating it
// if necessary.
func (r *Registry) DroppedPacketsOutbound() *metrics.MultiLabelMap[DropLabels] {
func (r *Registry) DroppedPacketsOutbound() *MultiLabelMap[DropLabels] {
r.initOnce()
return r.m.droppedPacketsOutbound
}
// DroppedPacketsInbound returns the inbound dropped packet metric.
func (r *Registry) DroppedPacketsInbound() *metrics.MultiLabelMap[DropLabels] {
func (r *Registry) DroppedPacketsInbound() *MultiLabelMap[DropLabels] {
r.initOnce()
return r.m.droppedPacketsInbound
}

29
util/usermetric/omit.go Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build ts_omit_usermetrics
package usermetric
type Registry struct {
m Metrics
}
func (*Registry) NewGauge(name, help string) *Gauge { return nil }
type MultiLabelMap[T comparable] = noopMap[T]
type noopMap[T comparable] struct{}
type Gauge struct{}
func (*Gauge) Set(float64) {}
func NewMultiLabelMapWithRegistry[T comparable](m *Registry, name string, promType, helpText string) *MultiLabelMap[T] {
return nil
}
func (*noopMap[T]) Add(T, int64) {}
func (*noopMap[T]) Set(T, any) {}
func (r *Registry) Handler(any, any) {} // no-op HTTP handler

View File

@@ -1,6 +1,8 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ts_omit_usermetrics
// Package usermetric provides a container and handler
// for user-facing metrics.
package usermetric
@@ -25,6 +27,10 @@ type Registry struct {
m Metrics
}
// MultiLabelMap is an alias for metrics.MultiLabelMap in the common case,
// or an alias to a lighter type when usermetrics are omitted from the build.
type MultiLabelMap[T comparable] = metrics.MultiLabelMap[T]
// NewMultiLabelMapWithRegistry creates and register a new
// MultiLabelMap[T] variable with the given name and returns it.
// The variable is registered with the userfacing metrics package.