Skip to content

Commit

Permalink
Add metrics for config file changes
Browse files Browse the repository at this point in the history
This uses code pieces from prometheus/alertmanager in https://github.com/prometheus/alertmanager/blob/main/config/coordinator.go#LL56C26-L56C26
licensed under Apache-2.0.

kube_state_metrics_config_hash{type="config", filename="config.yml"} 4.0061079457904e+13
kube_state_metrics_config_last_reload_success_timestamp_seconds{type="config", filename="config.yml"} 1.6697483049487052e+09
kube_state_metrics_config_last_reload_successful{type="config",
filename="config.yml"} 1

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
  • Loading branch information
mrueg committed Dec 1, 2022
1 parent 0cbabf9 commit b2682b8
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
2 changes: 1 addition & 1 deletion internal/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func RunKubeStateMetricsWrapper(opts *options.Options) {
}
}
ctx, cancel := context.WithCancel(context.Background())
if file := options.GetOptsConfigFile(*opts); file != "" {
if file := options.GetConfigFile(*opts); file != "" {
viper.SetConfigType("yaml")
viper.SetConfigFile(file)
if err := viper.ReadInConfig(); err != nil {
Expand Down
37 changes: 36 additions & 1 deletion pkg/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package app

import (
"context"
"crypto/md5" //nolint:gosec
"encoding/binary"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -99,9 +101,25 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options, factories .
ConstLabels: prometheus.Labels{"handler": "metrics"},
}, []string{"method"},
)
configHash := promauto.With(ksmMetricsRegistry).NewGaugeVec(
prometheus.GaugeOpts{
Name: "config_hash",
Help: "Hash of the currently loaded configuration.",
}, []string{"type", "filename"})
configSuccess := promauto.With(ksmMetricsRegistry).NewGaugeVec(
prometheus.GaugeOpts{
Name: "config_last_reload_successful",
Help: "Whether the last configuration reload attempt was successful.",
}, []string{"type", "filename"})
configSuccessTime := promauto.With(ksmMetricsRegistry).NewGaugeVec(
prometheus.GaugeOpts{
Name: "config_last_reload_success_timestamp_seconds",
Help: "Timestamp of the last successful configuration reload.",
}, []string{"type", "filename"})

storeBuilder.WithMetrics(ksmMetricsRegistry)

got := options.GetOptsConfigFile(*opts)
got := options.GetConfigFile(*opts)
if got != "" {
optsConfigFile, err := os.ReadFile(filepath.Clean(got))
if err != nil {
Expand All @@ -117,6 +135,12 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options, factories .
klog.Infof("misconfigured config detected, KSM will automatically reload on next write to the config")
klog.Infof("waiting for config to be fixed")
<-ctx.Done()
configSuccess.WithLabelValues("config", filepath.Clean(got)).Set(0)
} else {
configSuccess.WithLabelValues("config", filepath.Clean(got)).Set(1)
configSuccessTime.WithLabelValues("config", filepath.Clean(got)).SetToCurrentTime()
hash := md5HashAsMetricValue(optsConfigFile)
configHash.WithLabelValues("config", filepath.Clean(got)).Set(hash)
}
}
var resources []string
Expand Down Expand Up @@ -371,3 +395,14 @@ func buildMetricsServer(m *metricshandler.MetricsHandler, durationObserver prome
})
return mux
}

// md5HashAsMetricValue creates an md5 hash and returns the most significant bytes that fit into a float64
// Taken from https://github.com/prometheus/alertmanager/blob/6ef6e6868dbeb7984d2d577dd4bf75c65bf1904f/config/coordinator.go#L149
func md5HashAsMetricValue(data []byte) float64 {
sum := md5.Sum(data) //nolint:gosec
// We only want 48 bits as a float64 only has a 53 bit mantissa.
smallSum := sum[0:6]
bytes := make([]byte, 8)
copy(bytes, smallSum)
return float64(binary.LittleEndian.Uint64(bytes))
}
4 changes: 2 additions & 2 deletions pkg/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ type Options struct {
cmd *cobra.Command
}

// GetOptsConfigFile is the getter for --options-config-file value.
func GetOptsConfigFile(opt Options) string {
// GetConfigFile is the getter for --config value.
func GetConfigFile(opt Options) string {
return opt.Config
}

Expand Down

0 comments on commit b2682b8

Please sign in to comment.