Skip to content

Commit 18e0434

Browse files
authored
refactor: configurable cache metric (#1317)
Allows adding caches for different hcloud resources. See #1313
1 parent e05d38b commit 18e0434

5 files changed

Lines changed: 35 additions & 22 deletions

File tree

internal/cache/cache.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/prometheus/client_golang/prometheus"
910
"k8s.io/klog/v2"
10-
11-
"github.com/hetznercloud/hcloud-cloud-controller-manager/internal/metrics"
1211
)
1312

1413
type Mode string
@@ -63,9 +62,9 @@ type Cache[T any] struct {
6362
fetchAll func(ctx context.Context) ([]*T, error)
6463
getID func(value *T) int64
6564
getName func(value *T) string
66-
67-
defaultMaxAge time.Duration
68-
defaultMode Mode
65+
metric *prometheus.CounterVec
66+
defaultMaxAge time.Duration
67+
defaultMode Mode
6968

7069
byID map[int64]*entry[T]
7170
byName map[string]*entry[T]
@@ -79,6 +78,7 @@ func newCache[T any](
7978
fetchAll func(ctx context.Context) ([]*T, error),
8079
getID func(value *T) int64,
8180
getName func(value *T) string,
81+
metric *prometheus.CounterVec,
8282
defaultMode Mode,
8383
defaultMaxAge time.Duration,
8484
) *Cache[T] {
@@ -88,6 +88,7 @@ func newCache[T any](
8888
fetchAll: fetchAll,
8989
getID: getID,
9090
getName: getName,
91+
metric: metric,
9192

9293
defaultMode: defaultMode,
9394
defaultMaxAge: defaultMaxAge,
@@ -140,12 +141,12 @@ func (c *Cache[T]) All(ctx context.Context, opts ...RefreshOption) ([]*T, error)
140141
}
141142

142143
if now.Sub(refreshedAllAt) > refreshOpts.maxAge {
143-
metrics.CacheRequests.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
144+
c.metric.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
144145
if err := c.refreshAll(ctx); err != nil {
145146
return nil, err
146147
}
147148
} else {
148-
metrics.CacheRequests.WithLabelValues(subsystem, string(refreshOpts.mode), "hit").Inc()
149+
c.metric.WithLabelValues(subsystem, string(refreshOpts.mode), "hit").Inc()
149150
}
150151

151152
values := make([]*T, 0, len(c.byID))
@@ -166,7 +167,7 @@ func (c *Cache[T]) getFromCache(
166167
refreshOpts := newCacheRefreshOpts(c, opts...)
167168

168169
if refreshOpts.mode == ModeOff {
169-
metrics.CacheRequests.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
170+
c.metric.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
170171
klog.V(4).InfoS("cache mode is off: fetching entry from api", "subsystem", subsystem)
171172
return fetch()
172173
}
@@ -177,7 +178,7 @@ func (c *Cache[T]) getFromCache(
177178
now := time.Now()
178179

179180
if e := lookup(); e != nil && now.Sub(e.refreshedAt) <= refreshOpts.maxAge {
180-
metrics.CacheRequests.WithLabelValues(subsystem, string(refreshOpts.mode), "hit").Inc()
181+
c.metric.WithLabelValues(subsystem, string(refreshOpts.mode), "hit").Inc()
181182
klog.V(4).InfoS(
182183
"cache hit",
183184
"subsystem", subsystem,
@@ -201,7 +202,7 @@ func (c *Cache[T]) getFromCache(
201202
// Handled above through early return
202203
}
203204

204-
metrics.CacheRequests.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
205+
c.metric.WithLabelValues(subsystem, string(refreshOpts.mode), "miss").Inc()
205206

206207
// When the value is not found in the API, the entry is not removed from the cache.
207208
// Expired entries are only evicted after an hour and when a value is found.

internal/cache/cache_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing/synctest"
88
"time"
99

10+
"github.com/prometheus/client_golang/prometheus"
1011
"github.com/stretchr/testify/assert"
1112
"github.com/stretchr/testify/require"
1213

@@ -34,6 +35,10 @@ func newTestCache(mode Mode) *Cache[hcloud.Server] {
3435
nil,
3536
func(value *hcloud.Server) int64 { return value.ID },
3637
func(value *hcloud.Server) string { return value.Name },
38+
prometheus.NewCounterVec(
39+
prometheus.CounterOpts{Name: "test_cache_requests_total"},
40+
[]string{"subsystem", "mode", "result"},
41+
),
3742
mode,
3843
10*time.Second,
3944
)

internal/cache/servercache.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,21 @@ import (
44
"context"
55
"time"
66

7+
"github.com/prometheus/client_golang/prometheus"
8+
9+
"github.com/hetznercloud/hcloud-cloud-controller-manager/internal/metrics"
710
"github.com/hetznercloud/hcloud-go/v2/hcloud"
811
)
912

13+
var serverCacheRequests = prometheus.NewCounterVec(prometheus.CounterOpts{
14+
Name: "cloud_controller_manager_server_cache_requests_total",
15+
Help: "Total cache requests to the Servers API partitioned by subsystem, mode and result.",
16+
}, []string{"subsystem", "mode", "result"})
17+
18+
func init() {
19+
metrics.GetRegistry().MustRegister(serverCacheRequests)
20+
}
21+
1022
func NewServerCache(client *hcloud.Client, defaultMode Mode, defaultMaxAge time.Duration) *Cache[hcloud.Server] {
1123
return newCache[hcloud.Server](
1224
func(ctx context.Context, id int64) (*hcloud.Server, error) {
@@ -23,6 +35,7 @@ func NewServerCache(client *hcloud.Client, defaultMode Mode, defaultMaxAge time.
2335
},
2436
func(value *hcloud.Server) int64 { return value.ID },
2537
func(value *hcloud.Server) string { return value.Name },
38+
serverCacheRequests,
2639
defaultMode,
2740
defaultMaxAge,
2841
)

internal/cache/servercache_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func TestNewServerCache(t *testing.T) {
5151
require.NotNil(t, cache.fetchAll)
5252
require.NotNil(t, cache.getID)
5353
require.NotNil(t, cache.getName)
54+
require.NotNil(t, cache.metric)
5455

5556
ctx := t.Context()
5657

internal/metrics/metrics.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,13 @@ const (
3232
writeTimeout = 20 * time.Second
3333
)
3434

35-
var (
36-
OperationCalled = prometheus.NewCounterVec(prometheus.CounterOpts{
37-
Name: "cloud_controller_manager_operations_total",
38-
Help: "The total number of operation was called",
39-
}, []string{"op"})
40-
41-
CacheRequests = prometheus.NewCounterVec(prometheus.CounterOpts{
42-
Name: "cloud_controller_manager_server_cache_requests_total",
43-
Help: "Total cache requests partitioned by subsystem, mode and result.",
44-
}, []string{"subsystem", "mode", "result"})
45-
)
35+
var OperationCalled = prometheus.NewCounterVec(prometheus.CounterOpts{
36+
Name: "cloud_controller_manager_operations_total",
37+
Help: "The total number of operation was called",
38+
}, []string{"op"})
4639

4740
func init() {
48-
GetRegistry().MustRegister(OperationCalled, CacheRequests)
41+
GetRegistry().MustRegister(OperationCalled)
4942
}
5043

5144
func GetRegistry() prometheus.Registerer {

0 commit comments

Comments
 (0)