tailscale/metrics/metrics.go

127 lines
3.2 KiB
Go

// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package metrics contains expvar & Prometheus types and code used by
// Tailscale for monitoring.
package metrics
import (
"expvar"
"fmt"
)
// Set is a string-to-Var map variable that satisfies the expvar.Var
// interface.
//
// Semantically, this is mapped by tsweb's Prometheus exporter as a
// collection of unrelated variables exported with a common prefix.
//
// This lets us have tsweb recognize *expvar.Map for different
// purposes in the future. (Or perhaps all uses of expvar.Map will
// require explicit types like this one, declaring how we want tsweb
// to export it to Prometheus.)
type Set struct {
expvar.Map
}
// LabelMap is a string-to-Var map variable that satisfies the
// expvar.Var interface.
//
// Semantically, this is mapped by tsweb's Prometheus exporter as a
// collection of variables with the same name, with a varying label
// value. Use this to export things that are intuitively breakdowns
// into different buckets.
type LabelMap struct {
Label string
expvar.Map
}
// Get returns a direct pointer to the expvar.Int for key, creating it
// if necessary.
func (m *LabelMap) Get(key string) *expvar.Int {
m.Add(key, 0)
return m.Map.Get(key).(*expvar.Int)
}
// GetFloat returns a direct pointer to the expvar.Float for key, creating it
// if necessary.
func (m *LabelMap) GetFloat(key string) *expvar.Float {
m.AddFloat(key, 0.0)
return m.Map.Get(key).(*expvar.Float)
}
// CurrentFDs reports how many file descriptors are currently open.
//
// It only works on Linux. It returns zero otherwise.
func CurrentFDs() int {
return currentFDs()
}
// Distribution represents a set of values separated into individual "bins".
//
// Semantically, this is mapped by tsweb's Prometheus exporter as a collection
// of variables with the same name and the "le" ("less than or equal") label,
// one per bin. For example, with Bins=[1,2,10], the Prometheus variables will
// be:
// myvar_here{le="1"} 12
// myvar_here{le="2"} 34
// myvar_here{le="10"} 56
// myvar_here{le="inf"} 78
//
// Additionally, a "_max", "_min" and "_count" variable will be added
// containing the observed maximum, minimum, and total count of samples:
// myvar_here_max 99
// myvar_here_min 0
// myvar_here_count 180
type Distribution struct {
expvar.Map
Bins []float64
}
func (d *Distribution) Init() {
// Initialze all values to zero
for _, bin := range d.Bins {
d.Map.Add(fmt.Sprint(bin), 0)
}
d.Map.Add("Inf", 0)
d.Map.Add("count", 0)
d.Map.AddFloat("min", 0.0)
d.Map.AddFloat("max", 0.0)
}
func (d *Distribution) AddFloat(val float64) {
label := "Inf"
for _, bin := range d.Bins {
if val <= bin {
label = fmt.Sprint(bin)
break
}
}
d.Map.Add(label, 1)
d.Map.Add("count", 1)
min, ok := d.Map.Get("min").(*expvar.Float)
if ok {
if min.Value() > val {
min.Set(val)
}
} else {
min = new(expvar.Float)
min.Set(val)
d.Map.Set("min", min)
}
max, ok := d.Map.Get("max").(*expvar.Float)
if ok {
if max.Value() < val {
max.Set(val)
}
} else {
max = new(expvar.Float)
max.Set(val)
d.Map.Set("max", max)
}
}