Skip to content

Commit

Permalink
Migrate to kooper v2
Browse files Browse the repository at this point in the history
  • Loading branch information
ese committed Jan 11, 2022
1 parent 95d7133 commit 76adfbb
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 123 deletions.
15 changes: 9 additions & 6 deletions cmd/redisoperator/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"net/http"
"os"
Expand All @@ -9,7 +10,6 @@ import (
"time"

"github.com/prometheus/client_golang/prometheus"
kmetrics "github.com/spotahome/kooper/monitoring/metrics"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"

"github.com/spotahome/redis-operator/cmd/utils"
Expand Down Expand Up @@ -60,9 +60,8 @@ func (m *Main) Run() error {
}

// Create the metrics client.
registry := prometheus.NewRegistry()
metricsServer := metrics.NewPrometheusMetrics(m.flags.MetricsPath, metricsNamespace, http.DefaultServeMux, registry)
kooperMetricsServer := kmetrics.NewPrometheus(registry)
metricsRecorder := metrics.NewRecorder(metricsNamespace, prometheus.DefaultRegisterer)
//kooperMetricsServer := kmetrics.NewPrometheus(registry)

// Serve metrics.
go func() {
Expand All @@ -86,9 +85,13 @@ func (m *Main) Run() error {
redisClient := redis.New()

// Create operator and run.
redisfailoverOperator := redisfailover.New(m.flags.ToRedisOperatorConfig(), k8sservice, redisClient, metricsServer, kooperMetricsServer, m.logger)
redisfailoverOperator, err := redisfailover.New(m.flags.ToRedisOperatorConfig(), k8sservice, redisClient, metricsRecorder, m.logger)
if err != nil {
return err
}

go func() {
errC <- redisfailoverOperator.Run(m.stopC)
errC <- redisfailoverOperator.Run(context.Background())
}()

// Await signals.
Expand Down
45 changes: 23 additions & 22 deletions log/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@ var Dummy = DummyLogger{}
// DummyLogger is an empty logger mainly used for tests
type DummyLogger struct{}

func (l DummyLogger) Debug(...interface{}) {}
func (l DummyLogger) Debugln(...interface{}) {}
func (l DummyLogger) Debugf(string, ...interface{}) {}
func (l DummyLogger) Info(...interface{}) {}
func (l DummyLogger) Infoln(...interface{}) {}
func (l DummyLogger) Infof(string, ...interface{}) {}
func (l DummyLogger) Warn(...interface{}) {}
func (l DummyLogger) Warnln(...interface{}) {}
func (l DummyLogger) Warnf(string, ...interface{}) {}
func (l DummyLogger) Warningf(format string, args ...interface{}) {}
func (l DummyLogger) Error(...interface{}) {}
func (l DummyLogger) Errorln(...interface{}) {}
func (l DummyLogger) Errorf(string, ...interface{}) {}
func (l DummyLogger) Fatal(...interface{}) {}
func (l DummyLogger) Fatalln(...interface{}) {}
func (l DummyLogger) Fatalf(string, ...interface{}) {}
func (l DummyLogger) Panic(...interface{}) {}
func (l DummyLogger) Panicln(...interface{}) {}
func (l DummyLogger) Panicf(string, ...interface{}) {}
func (l DummyLogger) With(key string, value interface{}) Logger { return l }
func (l DummyLogger) WithField(key string, value interface{}) Logger { return l }
func (l DummyLogger) Set(level Level) error { return nil }
func (l DummyLogger) Debug(...interface{}) {}
func (l DummyLogger) Debugln(...interface{}) {}
func (l DummyLogger) Debugf(string, ...interface{}) {}
func (l DummyLogger) Info(...interface{}) {}
func (l DummyLogger) Infoln(...interface{}) {}
func (l DummyLogger) Infof(string, ...interface{}) {}
func (l DummyLogger) Warn(...interface{}) {}
func (l DummyLogger) Warnln(...interface{}) {}
func (l DummyLogger) Warnf(string, ...interface{}) {}
func (l DummyLogger) Warningf(format string, args ...interface{}) {}
func (l DummyLogger) Error(...interface{}) {}
func (l DummyLogger) Errorln(...interface{}) {}
func (l DummyLogger) Errorf(string, ...interface{}) {}
func (l DummyLogger) Fatal(...interface{}) {}
func (l DummyLogger) Fatalln(...interface{}) {}
func (l DummyLogger) Fatalf(string, ...interface{}) {}
func (l DummyLogger) Panic(...interface{}) {}
func (l DummyLogger) Panicln(...interface{}) {}
func (l DummyLogger) Panicf(string, ...interface{}) {}
func (l DummyLogger) With(key string, value interface{}) Logger { return l }
func (l DummyLogger) WithField(key string, value interface{}) Logger { return l }
func (l DummyLogger) WithFields(values map[string]interface{}) Logger { return l }
func (l DummyLogger) Set(level Level) error { return nil }
5 changes: 5 additions & 0 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Logger interface {

With(key string, value interface{}) Logger
WithField(key string, value interface{}) Logger
WithFields(values map[string]interface{}) Logger
Set(level Level) error
}

Expand Down Expand Up @@ -128,6 +129,10 @@ func (l logger) WithField(key string, value interface{}) Logger {
return &logger{l.entry.WithField(key, value)}
}

func (l logger) WithFields(values map[string]interface{}) Logger {
return &logger{l.entry.WithFields(logrus.Fields(values))}
}

func (l *logger) Set(level Level) error {
leLev, err := logrus.ParseLevel(string(level))
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion metrics/dummy.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package metrics

import koopercontroller "github.com/spotahome/kooper/v2/controller"

// Dummy is a handy instnce of a dummy instrumenter, most of the times it will be used on tests.
var Dummy = &dummy{}

// dummy is a dummy implementation of Instrumenter.
type dummy struct{}
type dummy struct {
koopercontroller.MetricsRecorder
}

func (d *dummy) SetClusterOK(namespace string, name string) {}
func (d *dummy) SetClusterError(namespace string, name string) {}
Expand Down
55 changes: 23 additions & 32 deletions metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
package metrics

import (
"net/http"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
koopercontroller "github.com/spotahome/kooper/v2/controller"
kooperprometheus "github.com/spotahome/kooper/v2/metrics/prometheus"
)

const (
promControllerSubsystem = "controller"
)

// Instrumenter is the interface that will collect the metrics and has ability to send/expose those metrics.
type Instrumenter interface {
type Recorder interface {
koopercontroller.MetricsRecorder

SetClusterOK(namespace string, name string)
SetClusterError(namespace string, name string)
DeleteCluster(namespace string, name string)
}

// PromMetrics implements the instrumenter so the metrics can be managed by Prometheus.
type PromMetrics struct {
type recorder struct {
// Metrics fields.
clusterOK *prometheus.GaugeVec // clusterOk is the status of a cluster

// Instrumentation fields.
registry prometheus.Registerer
path string
mux *http.ServeMux
koopercontroller.MetricsRecorder
}

// NewPrometheusMetrics returns a new PromMetrics object.
func NewPrometheusMetrics(path string, namespace string, mux *http.ServeMux, registry *prometheus.Registry) *PromMetrics {
func NewRecorder(namespace string, reg prometheus.Registerer) Recorder {
// Create metrics.
clusterOK := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: namespace,
Expand All @@ -40,40 +38,33 @@ func NewPrometheusMetrics(path string, namespace string, mux *http.ServeMux, reg
}, []string{"namespace", "name"})

// Create the instance.
p := &PromMetrics{
r := recorder{
clusterOK: clusterOK,

registry: registry,
path: path,
mux: mux,
MetricsRecorder: kooperprometheus.New(kooperprometheus.Config{
Registerer: reg,
}),
}

// Register metrics on prometheus.
p.register()

// Register prometheus handler so we can serve the metrics.
handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
mux.Handle(path, handler)

return p
}
// Register metrics.
reg.MustRegister(
r.clusterOK,
)

// register will register all the required prometheus metrics on the Prometheus collector.
func (p *PromMetrics) register() {
p.registry.MustRegister(p.clusterOK)
return r
}

// SetClusterOK set the cluster status to OK
func (p *PromMetrics) SetClusterOK(namespace string, name string) {
p.clusterOK.WithLabelValues(namespace, name).Set(1)
func (r recorder) SetClusterOK(namespace string, name string) {
r.clusterOK.WithLabelValues(namespace, name).Set(1)
}

// SetClusterError set the cluster status to Error
func (p *PromMetrics) SetClusterError(namespace string, name string) {
p.clusterOK.WithLabelValues(namespace, name).Set(0)
func (r recorder) SetClusterError(namespace string, name string) {
r.clusterOK.WithLabelValues(namespace, name).Set(0)
}

// DeleteCluster set the cluster status to Error
func (p *PromMetrics) DeleteCluster(namespace string, name string) {
p.clusterOK.DeleteLabelValues(namespace, name)
func (r recorder) DeleteCluster(namespace string, name string) {
r.clusterOK.DeleteLabelValues(namespace, name)
}
60 changes: 29 additions & 31 deletions metrics/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"

"github.com/stretchr/testify/assert"

Expand All @@ -17,14 +18,14 @@ func TestPrometheusMetrics(t *testing.T) {

tests := []struct {
name string
addMetrics func(pm *metrics.PromMetrics)
addMetrics func(rec metrics.Recorder)
expMetrics []string
expCode int
}{
{
name: "Setting OK should give an OK",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns"} 1`,
Expand All @@ -33,8 +34,8 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Setting Error should give an Error",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterError("testns", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterError("testns", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns"} 0`,
Expand All @@ -43,9 +44,9 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Setting Error after ok should give an Error",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns", "test")
pm.SetClusterError("testns", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns", "test")
rec.SetClusterError("testns", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns"} 0`,
Expand All @@ -54,9 +55,9 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Setting OK after Error should give an OK",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterError("testns", "test")
pm.SetClusterOK("testns", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterError("testns", "test")
rec.SetClusterOK("testns", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns"} 1`,
Expand All @@ -65,9 +66,9 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Multiple clusters should appear",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns", "test")
pm.SetClusterOK("testns", "test2")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns", "test")
rec.SetClusterOK("testns", "test2")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns"} 1`,
Expand All @@ -77,9 +78,9 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Same name on different namespaces should appear",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns1", "test")
pm.SetClusterOK("testns2", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns1", "test")
rec.SetClusterOK("testns2", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns1"} 1`,
Expand All @@ -89,19 +90,19 @@ func TestPrometheusMetrics(t *testing.T) {
},
{
name: "Deleting a cluster should remove it",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns1", "test")
pm.DeleteCluster("testns1", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns1", "test")
rec.DeleteCluster("testns1", "test")
},
expMetrics: []string{},
expCode: http.StatusOK,
},
{
name: "Deleting a cluster should remove only the desired one",
addMetrics: func(pm *metrics.PromMetrics) {
pm.SetClusterOK("testns1", "test")
pm.SetClusterOK("testns2", "test")
pm.DeleteCluster("testns1", "test")
addMetrics: func(rec metrics.Recorder) {
rec.SetClusterOK("testns1", "test")
rec.SetClusterOK("testns2", "test")
rec.DeleteCluster("testns1", "test")
},
expMetrics: []string{
`my_metrics_controller_cluster_ok{name="test",namespace="testns2"} 1`,
Expand All @@ -114,20 +115,17 @@ func TestPrometheusMetrics(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
assert := assert.New(t)

path := "/awesome-metrics"

// Create the muxer for testing.
mx := http.NewServeMux()
reg := prometheus.NewRegistry()
pm := metrics.NewPrometheusMetrics(path, "my_metrics", mx, reg)
rec := metrics.NewRecorder("my_metrics", reg)

// Add metrics to prometheus.
test.addMetrics(pm)
test.addMetrics(rec)

// Make the request to the metrics.
req := httptest.NewRequest("GET", path, nil)
h := promhttp.HandlerFor(reg, promhttp.HandlerOpts{})
w := httptest.NewRecorder()
mx.ServeHTTP(w, req)
h.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/metrics", nil))

resp := w.Result()
if assert.Equal(test.expCode, resp.StatusCode) {
Expand Down
Loading

0 comments on commit 76adfbb

Please sign in to comment.