mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-22 16:46:29 +00:00
client/local: add method to set gauge metric to a value
The existing client metric methods only support incrementing (or decrementing) a delta value. This new method allows setting the metric to a specific value. Updates tailscale/corp#35327 Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d Signed-off-by: Will Norris <will@tailscale.com>
This commit is contained in:
@@ -43,6 +43,7 @@ import (
|
||||
"tailscale.com/types/appctype"
|
||||
"tailscale.com/types/dnstype"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/eventbus"
|
||||
)
|
||||
|
||||
@@ -385,18 +386,14 @@ func (lc *Client) IncrementCounter(ctx context.Context, name string, delta int)
|
||||
if !buildfeatures.HasClientMetrics {
|
||||
return nil
|
||||
}
|
||||
type metricUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value int `json:"value"` // amount to increment by
|
||||
}
|
||||
if delta < 0 {
|
||||
return errors.New("negative delta not allowed")
|
||||
}
|
||||
_, err := lc.send(ctx, "POST", "/localapi/v0/upload-client-metrics", 200, jsonBody([]metricUpdate{{
|
||||
_, err := lc.send(ctx, "POST", "/localapi/v0/upload-client-metrics", 200, jsonBody([]clientmetric.MetricUpdate{{
|
||||
Name: name,
|
||||
Type: "counter",
|
||||
Value: delta,
|
||||
Op: "add",
|
||||
}}))
|
||||
return err
|
||||
}
|
||||
@@ -405,15 +402,23 @@ func (lc *Client) IncrementCounter(ctx context.Context, name string, delta int)
|
||||
// metric by the given delta. If the metric has yet to exist, a new gauge
|
||||
// metric is created and initialized to delta. The delta value can be negative.
|
||||
func (lc *Client) IncrementGauge(ctx context.Context, name string, delta int) error {
|
||||
type metricUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value int `json:"value"` // amount to increment by
|
||||
}
|
||||
_, err := lc.send(ctx, "POST", "/localapi/v0/upload-client-metrics", 200, jsonBody([]metricUpdate{{
|
||||
_, err := lc.send(ctx, "POST", "/localapi/v0/upload-client-metrics", 200, jsonBody([]clientmetric.MetricUpdate{{
|
||||
Name: name,
|
||||
Type: "gauge",
|
||||
Value: delta,
|
||||
Op: "add",
|
||||
}}))
|
||||
return err
|
||||
}
|
||||
|
||||
// SetGauge sets the value of a Tailscale daemon's gauge metric to the given value.
|
||||
// If the metric has yet to exist, a new gauge metric is created and initialized to value.
|
||||
func (lc *Client) SetGauge(ctx context.Context, name string, value int) error {
|
||||
_, err := lc.send(ctx, "POST", "/localapi/v0/upload-client-metrics", 200, jsonBody([]clientmetric.MetricUpdate{{
|
||||
Name: name,
|
||||
Type: "gauge",
|
||||
Value: value,
|
||||
Op: "set",
|
||||
}}))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ func (menu *Menu) Run(client *local.Client) {
|
||||
case <-menu.bgCtx.Done():
|
||||
}
|
||||
}()
|
||||
go menu.lc.IncrementGauge(menu.bgCtx, "systray_running", 1)
|
||||
defer menu.lc.IncrementGauge(menu.bgCtx, "systray_running", -1)
|
||||
go menu.lc.SetGauge(menu.bgCtx, "systray_running", 1)
|
||||
defer menu.lc.SetGauge(menu.bgCtx, "systray_running", 0)
|
||||
|
||||
systray.Run(menu.onReady, menu.onExit)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
||||
tailscale.com/types/tkatype from tailscale.com/client/local+
|
||||
tailscale.com/types/views from tailscale.com/ipn+
|
||||
tailscale.com/util/cibuild from tailscale.com/health+
|
||||
tailscale.com/util/clientmetric from tailscale.com/net/netmon
|
||||
tailscale.com/util/clientmetric from tailscale.com/net/netmon+
|
||||
tailscale.com/util/cloudenv from tailscale.com/hostinfo+
|
||||
tailscale.com/util/ctxkey from tailscale.com/tsweb+
|
||||
💣 tailscale.com/util/deephash from tailscale.com/util/syspolicy/setting
|
||||
|
||||
@@ -1283,13 +1283,8 @@ func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Reques
|
||||
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
type clientMetricJSON struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // one of "counter" or "gauge"
|
||||
Value int `json:"value"` // amount to increment metric by
|
||||
}
|
||||
|
||||
var clientMetrics []clientMetricJSON
|
||||
var clientMetrics []clientmetric.MetricUpdate
|
||||
if err := json.NewDecoder(r.Body).Decode(&clientMetrics); err != nil {
|
||||
http.Error(w, "invalid JSON body", http.StatusBadRequest)
|
||||
return
|
||||
@@ -1299,14 +1294,12 @@ func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Reques
|
||||
defer metricsMu.Unlock()
|
||||
|
||||
for _, m := range clientMetrics {
|
||||
if metric, ok := metrics[m.Name]; ok {
|
||||
metric.Add(int64(m.Value))
|
||||
} else {
|
||||
metric, ok := metrics[m.Name]
|
||||
if !ok {
|
||||
if clientmetric.HasPublished(m.Name) {
|
||||
http.Error(w, "Already have a metric named "+m.Name, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var metric *clientmetric.Metric
|
||||
switch m.Type {
|
||||
case "counter":
|
||||
metric = clientmetric.NewCounter(m.Name)
|
||||
@@ -1317,7 +1310,15 @@ func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
metrics[m.Name] = metric
|
||||
}
|
||||
switch m.Op {
|
||||
case "add", "":
|
||||
metric.Add(int64(m.Value))
|
||||
case "set":
|
||||
metric.Set(int64(m.Value))
|
||||
default:
|
||||
http.Error(w, "Unknown metric op "+m.Op, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,20 @@ const (
|
||||
TypeCounter
|
||||
)
|
||||
|
||||
// MetricUpdate requests that a client metric value be updated.
|
||||
//
|
||||
// This is the request body sent to /localapi/v0/upload-client-metrics.
|
||||
type MetricUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // one of "counter" or "gauge"
|
||||
Value int `json:"value"` // amount to increment by or set
|
||||
|
||||
// Op indicates if Value is added to the existing metric value,
|
||||
// or if the metric is set to Value.
|
||||
// One of "add" or "set". If empty, defaults to "add".
|
||||
Op string `json:"op"`
|
||||
}
|
||||
|
||||
// Metric is an integer metric value that's tracked over time.
|
||||
//
|
||||
// It's safe for concurrent use.
|
||||
|
||||
@@ -13,6 +13,13 @@ func (*Metric) Value() int64 { return 0 }
|
||||
func (*Metric) Register(expvarInt any) {}
|
||||
func (*Metric) UnregisterAll() {}
|
||||
|
||||
type MetricUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value int `json:"value"`
|
||||
Op string `json:"op"`
|
||||
}
|
||||
|
||||
func HasPublished(string) bool { panic("unreachable") }
|
||||
func EncodeLogTailMetricsDelta() string { return "" }
|
||||
func WritePrometheusExpositionFormat(any) {}
|
||||
|
||||
Reference in New Issue
Block a user