|
|
|
@ -11,6 +11,7 @@ package appc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/netip"
|
|
|
|
|
"slices"
|
|
|
|
|
"strings"
|
|
|
|
@ -21,6 +22,7 @@ import (
|
|
|
|
|
"golang.org/x/net/dns/dnsmessage"
|
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
|
"tailscale.com/types/views"
|
|
|
|
|
"tailscale.com/util/clientmetric"
|
|
|
|
|
"tailscale.com/util/dnsname"
|
|
|
|
|
"tailscale.com/util/execqueue"
|
|
|
|
|
"tailscale.com/util/mak"
|
|
|
|
@ -78,6 +80,42 @@ type RouteAdvertiser interface {
|
|
|
|
|
UnadvertiseRoute(...netip.Prefix) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
metricStoreRoutesRateBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000}
|
|
|
|
|
metricStoreRoutesNBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000, 10000}
|
|
|
|
|
metricStoreRoutesRate []*clientmetric.Metric
|
|
|
|
|
metricStoreRoutesN []*clientmetric.Metric
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func initMetricStoreRoutes() {
|
|
|
|
|
for _, n := range metricStoreRoutesRateBuckets {
|
|
|
|
|
metricStoreRoutesRate = append(metricStoreRoutesRate, clientmetric.NewCounter(fmt.Sprintf("appc_store_routes_rate_%d", n)))
|
|
|
|
|
}
|
|
|
|
|
metricStoreRoutesRate = append(metricStoreRoutesRate, clientmetric.NewCounter("appc_store_routes_rate_over"))
|
|
|
|
|
for _, n := range metricStoreRoutesNBuckets {
|
|
|
|
|
metricStoreRoutesN = append(metricStoreRoutesN, clientmetric.NewCounter(fmt.Sprintf("appc_store_routes_n_routes_%d", n)))
|
|
|
|
|
}
|
|
|
|
|
metricStoreRoutesN = append(metricStoreRoutesN, clientmetric.NewCounter("appc_store_routes_n_routes_over"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func recordMetric(val int64, buckets []int64, metrics []*clientmetric.Metric) {
|
|
|
|
|
if len(buckets) < 1 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// finds the first bucket where val <=, or len(buckets) if none match
|
|
|
|
|
// for bucket values of 1, 10, 100; 0-1 goes to [0], 2-10 goes to [1], 11-100 goes to [2], 101+ goes to [3]
|
|
|
|
|
bucket, _ := slices.BinarySearch(buckets, val)
|
|
|
|
|
metrics[bucket].Add(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func metricStoreRoutes(rate, nRoutes int64) {
|
|
|
|
|
if len(metricStoreRoutesRate) == 0 {
|
|
|
|
|
initMetricStoreRoutes()
|
|
|
|
|
}
|
|
|
|
|
recordMetric(rate, metricStoreRoutesRateBuckets, metricStoreRoutesRate)
|
|
|
|
|
recordMetric(nRoutes, metricStoreRoutesNBuckets, metricStoreRoutesN)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RouteInfo is a data structure used to persist the in memory state of an AppConnector
|
|
|
|
|
// so that we can know, even after a restart, which routes came from ACLs and which were
|
|
|
|
|
// learned from domains.
|
|
|
|
@ -141,6 +179,7 @@ func NewAppConnector(logf logger.Logf, routeAdvertiser RouteAdvertiser, routeInf
|
|
|
|
|
}
|
|
|
|
|
ac.writeRateMinute = newRateLogger(time.Now, time.Minute, func(c int64, s time.Time, l int64) {
|
|
|
|
|
ac.logf("routeInfo write rate: %d in minute starting at %v (%d routes)", c, s, l)
|
|
|
|
|
metricStoreRoutes(c, l)
|
|
|
|
|
})
|
|
|
|
|
ac.writeRateDay = newRateLogger(time.Now, 24*time.Hour, func(c int64, s time.Time, l int64) {
|
|
|
|
|
ac.logf("routeInfo write rate: %d in 24 hours starting at %v (%d routes)", c, s, l)
|
|
|
|
|