18794: Export config timestamp/hash as prometheus metric.
authorTom Clegg <tom@curii.com>
Fri, 8 Apr 2022 20:05:26 +0000 (16:05 -0400)
committerTom Clegg <tom@curii.com>
Tue, 26 Apr 2022 15:19:20 +0000 (11:19 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/config/load.go
lib/config/load_test.go
lib/service/cmd.go

index 28f300e3bb632596628ec8cd8e04c154344b7698..d03ef5388d901d9c51bda1a5cc5ef90fea1e7a62 100644 (file)
@@ -6,6 +6,7 @@ package config
 
 import (
        "bytes"
+       "crypto/sha256"
        _ "embed"
        "encoding/json"
        "errors"
@@ -22,6 +23,7 @@ import (
        "git.arvados.org/arvados.git/sdk/go/arvados"
        "github.com/ghodss/yaml"
        "github.com/imdario/mergo"
+       "github.com/prometheus/client_golang/prometheus"
        "github.com/sirupsen/logrus"
 )
 
@@ -569,3 +571,20 @@ func (ldr *Loader) autofillPreemptible(label string, cc *arvados.Cluster) {
        }
 
 }
+
+// RegisterMetrics registers metrics showing the timestamp and content
+// hash of the currently loaded config.
+//
+// Must not be called more than once for a given registry. Must not be
+// called before Load(). Metrics are not updated by subsequent calls
+// to Load().
+func (ldr *Loader) RegisterMetrics(reg *prometheus.Registry) {
+       vec := prometheus.NewGaugeVec(prometheus.GaugeOpts{
+               Namespace: "arvados",
+               Subsystem: "config",
+               Name:      "source_timestamp_seconds",
+               Help:      "Timestamp of config file when it was loaded.",
+       }, []string{"sha256"})
+       vec.WithLabelValues(fmt.Sprintf("%x", sha256.Sum256(ldr.configdata))).Set(float64(ldr.sourceTimestamp.UnixNano()) / 1e9)
+       reg.MustRegister(vec)
+}
index cef7ea944bb08cd15357f9e4c58341a2135419f2..b43cda38c8a7a7304ea0a9fd74148e74be99d2d8 100644 (file)
@@ -20,6 +20,8 @@ import (
        "git.arvados.org/arvados.git/sdk/go/arvados"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
        "github.com/ghodss/yaml"
+       "github.com/prometheus/client_golang/prometheus"
+       "github.com/prometheus/common/expfmt"
        "github.com/sirupsen/logrus"
        "golang.org/x/sys/unix"
        check "gopkg.in/check.v1"
@@ -798,5 +800,15 @@ func (s *LoadSuite) TestSourceTimestamp(c *check.C) {
                c.Assert(err, check.IsNil)
                c.Check(cfg.SourceTimestamp, check.Equals, cfg.SourceTimestamp.UTC())
                c.Check(int(cfg.SourceTimestamp.Sub(trial.expectTime).Seconds()), check.Equals, 0)
+
+               var buf bytes.Buffer
+               reg := prometheus.NewRegistry()
+               ldr.RegisterMetrics(reg)
+               enc := expfmt.NewEncoder(&buf, expfmt.FmtText)
+               got, _ := reg.Gather()
+               for _, mf := range got {
+                       enc.Encode(mf)
+               }
+               c.Check(buf.String(), check.Matches, `# HELP .*\n# TYPE .*\narvados_config_source_timestamp_seconds{sha256="83aea5d82eb1d53372cd65c936c60acc1c6ef946e61977bbca7cfea709d201a8"} \Q`+fmt.Sprintf("%g", float64(cfg.SourceTimestamp.UnixNano())/1e9)+`\E\n`)
        }
 }
index 1ed2ac1314c3618014269450cbc8e78921988657..6f5efa5cb7e968692eac444967e7d4afbca3b16a 100644 (file)
@@ -117,6 +117,8 @@ func (c *command) RunCommand(prog string, args []string, stdin io.Reader, stdout
        ctx = context.WithValue(ctx, contextKeyURL{}, listenURL)
 
        reg := prometheus.NewRegistry()
+       loader.RegisterMetrics(reg)
+
        handler := c.newHandler(ctx, cluster, cluster.SystemRootToken, reg)
        if err = handler.CheckHealth(); err != nil {
                return 1