Skip to content

Commit 493b38c

Browse files
authored
Add ::path-cache to registry collectors map metadata (#59)
1 parent 5530bdc commit 493b38c

File tree

9 files changed

+174
-20
lines changed

9 files changed

+174
-20
lines changed

dev/bench.clj

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
(ns bench
2+
(:require [clojure.test.check.generators :as gen]
3+
[iapetos.core :as prometheus]
4+
[iapetos.registry :as r]
5+
[iapetos.registry.collectors :as c]
6+
[iapetos.test.generators :as g]
7+
[jmh.core :as jmh])
8+
(:import [iapetos.registry IapetosRegistry]))
9+
10+
(defn metrics
11+
[metric-count]
12+
(gen/sample g/metric metric-count))
13+
14+
(def dirty-string-metric
15+
(gen/let [first-char gen/char-alpha
16+
invalid-chars (gen/return (apply str (map char (range 33 45))))
17+
last-char gen/char-alphanumeric
18+
rest-chars gen/string-alphanumeric]
19+
(gen/return
20+
(str
21+
(apply str first-char invalid-chars rest-chars)
22+
last-char))))
23+
24+
(defn dirty-metrics
25+
[metric-count]
26+
(gen/sample dirty-string-metric metric-count))
27+
28+
;; JMH fns
29+
30+
(defn collectors
31+
[^IapetosRegistry registry]
32+
(.-collectors registry))
33+
34+
(defn register-collectors
35+
[metrics]
36+
(reduce (fn [reg metric]
37+
(r/register reg metric (prometheus/counter metric)))
38+
(r/create)
39+
metrics))
40+
41+
(defn lookup
42+
[collectors metric]
43+
(c/lookup collectors metric {}))
44+
45+
(def bench-env
46+
{:benchmarks [{:name :registry-lookup
47+
:fn `lookup
48+
:args [:state/collectors :state/metric]}
49+
50+
{:name :dirty-registry-lookup
51+
:fn `lookup
52+
:args [:state/dirty-collectors :state/dirty-metric]}]
53+
54+
:states {:dirty-metrics {:fn `dirty-metrics :args [:param/metric-count]}
55+
:dirty-metric {:fn `rand-nth :args [:state/dirty-metrics]}
56+
:dirty-registry {:fn `register-collectors :args [:state/dirty-metrics]}
57+
:dirty-collectors {:fn `collectors :args [:state/dirty-registry]}
58+
59+
:metrics {:fn `metrics :args [:param/metric-count]}
60+
:metric {:fn `rand-nth :args [:state/metrics]}
61+
:registry {:fn `register-collectors :args [:state/metrics]}
62+
:collectors {:fn `collectors :args [:state/registry]}}
63+
64+
:params {:metric-count 500}
65+
66+
:options {:registry-lookup {:measurement {:iterations 1000}}
67+
:dirty-registry-lookup {:measurement {:iterations 1000}}
68+
:jmh/default {:mode :average
69+
:output-time-unit :us
70+
:measurement {:iterations 1000
71+
:count 1}}}})
72+
73+
(def bench-opts
74+
{:type :quick
75+
:params {:metric-count 500}})
76+
77+
(comment
78+
79+
(map #(select-keys % [:fn :mode :name :score]) (jmh/run bench-env bench-opts))
80+
81+
)

project.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
[io.prometheus/simpleclient_hotspot "0.12.0" :scope "provided"]]
1818
:profiles {:dev
1919
{:dependencies [[org.clojure/test.check "1.1.0"]
20-
[aleph "0.4.6"]]
20+
[aleph "0.4.6"]
21+
[jmh-clojure "0.4.1"]]
22+
:source-paths ["dev"]
2123
:global-vars {*warn-on-reflection* true}}
2224
:codox
2325
{:plugins [[lein-codox "0.10.0"]]

src/iapetos/collector.clj

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
registries.")
1616
(metric [this]
1717
"Return a `iapetos.metric/Metric` for this collector.")
18+
(metric-id [this]
19+
"Return user supplied (unsanitized) identifier for this collector.")
1820
(label-instance [this instance values]
1921
"Add labels to the given collector instance produced by `instantiate`."))
2022

@@ -55,6 +57,7 @@
5557
(defrecord SimpleCollectorImpl [type
5658
namespace
5759
name
60+
metric-id
5861
description
5962
subsystem
6063
labels
@@ -74,6 +77,8 @@
7477
(metric [_]
7578
{:name name
7679
:namespace namespace})
80+
(metric-id [_]
81+
metric-id)
7782
(label-instance [_ instance values]
7883
(set-labels instance labels values)))
7984

@@ -85,14 +90,16 @@
8590
^String subsystem
8691
^String description
8792
labels
88-
lazy?]}
93+
lazy?]
94+
::metric/keys [id]}
8995
collector-type
9096
builder-constructor]
9197
{:pre [type name namespace description]}
9298
(map->SimpleCollectorImpl
9399
{:type collector-type
94100
:namespace namespace
95101
:name name
102+
:metric-id id
96103
:description description
97104
:subsystem subsystem
98105
:labels (label-names labels)
@@ -119,6 +126,8 @@
119126
this)
120127
(metric [this]
121128
(raw-metric this))
129+
(metric-id [this]
130+
(hash this))
122131
(label-instance [_ instance values]
123132
(if-not (empty? values)
124133
(throw (UnsupportedOperationException.))
@@ -133,5 +142,7 @@
133142
(instantiate collector options))
134143
(metric [_]
135144
metric)
145+
(metric-id [_]
146+
metric)
136147
(label-instance [_ instance values]
137148
(label-instance collector instance values))))

src/iapetos/collector/exceptions.clj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
(collector/instantiate counter registry-options))
4444
(metric [this]
4545
(collector/metric counter))
46+
(metric-id [this]
47+
(collector/metric-id counter))
4648
(label-instance [_ instance values]
4749
(->ExceptionCounterChild counter instance values)))
4850

src/iapetos/metric.clj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
(defn as-map
6464
[metric additional-keys]
65-
(merge
66-
(metric-name metric)
67-
additional-keys))
65+
(merge (metric-name metric)
66+
additional-keys
67+
;; user supplied (unsanitized) identifier e.g., :app/runs-total
68+
{::id metric}))

src/iapetos/registry.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
registry-name
5757
registry
5858
(update options :subsystem utils/join-subsystem subsystem-name)
59-
{}))
59+
(collectors/initialize)))
6060
(get [_ metric labels]
6161
(collectors/by collectors metric labels options))
6262
(raw [_]

src/iapetos/registry/collectors.clj

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
(ns iapetos.registry.collectors
2-
(:require [iapetos.registry.utils :as utils]
2+
(:require [iapetos.metric :as metric]
3+
[iapetos.registry.utils :as utils]
34
[iapetos.collector :as collector])
45
(:import [io.prometheus.client Collector CollectorRegistry]))
56

67
;; ## Init
78

89
(defn initialize
10+
"Initialize map for collectors.
11+
12+
- ::path-cache meta used to prevent additional metric path computation
13+
requiring metric name sanitization."
914
[]
10-
{})
15+
^{::path-cache {}} {})
1116

1217
;; ## Management
1318

@@ -39,22 +44,26 @@
3944
instance (collector/instantiate collector options)]
4045
(-> {:collector collector
4146
:metric metric
47+
:cache-key [(collector/metric-id collector) options]
4248
:path path
4349
:raw instance
4450
:register (register-collector-delay registry instance)
4551
:unregister (unregister-collector-delay registry instance)}
4652
(warn-lazy-deprecation!))))
4753

4854
(defn insert
49-
[collectors {:keys [path] :as collector}]
50-
(assoc-in collectors path collector))
55+
[collectors {:keys [path cache-key] :as collector}]
56+
(-> collectors
57+
(vary-meta update ::path-cache assoc cache-key path)
58+
(assoc-in path collector)))
5159

5260
(defn delete
53-
[collectors {:keys [path] :as collector}]
54-
(update-in collectors
55-
(butlast path)
56-
dissoc
57-
(last path)))
61+
[collectors {:keys [path cache-key] :as _collector}]
62+
(-> collectors
63+
(vary-meta update ::path-cache dissoc cache-key)
64+
(update-in (butlast path)
65+
dissoc
66+
(last path))))
5867

5968
(defn unregister
6069
[collectors {:keys [register unregister] :as collector}]
@@ -69,9 +78,9 @@
6978

7079
(defn clear
7180
[collectors]
72-
(->> (for [[namespace vs] collectors
73-
[subsystem vs] vs
74-
[_ collector] vs]
81+
(->> (for [[_namespace vs] collectors
82+
[_subsystem vs] vs
83+
[_name collector] vs]
7584
collector)
7685
(reduce unregister collectors)))
7786

@@ -83,7 +92,9 @@
8392

8493
(defn lookup
8594
[collectors metric options]
86-
(some->> (utils/metric->path metric options)
95+
(some->> (or (get-in (meta collectors)
96+
[::path-cache [metric options]])
97+
(utils/metric->path metric options))
8798
(get-in collectors)))
8899

89100
(defn by

test/iapetos/metric_test.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@
4444
(let [{:keys [name namespace] :as r} (metric/as-map metric additional-keys)]
4545
(and (re-matches #"[a-zA-Z0-9_]+" name)
4646
(re-matches #"[a-zA-Z0-9_]+" namespace)
47-
(= additional-keys (dissoc r :name :namespace))))))
47+
(= additional-keys (dissoc r :name :namespace ::metric/id))
48+
(= metric (::metric/id r))))))
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
(ns iapetos.registry.collectors-test
2+
(:require [clojure.test.check
3+
[generators :as gen]
4+
[properties :as prop]
5+
[clojure-test :refer [defspec]]]
6+
[clojure.test :refer :all]
7+
[iapetos.test.generators :as g]
8+
[iapetos.core :as prometheus]
9+
[iapetos.collector :as collector]
10+
[iapetos.registry.collectors :as c])
11+
(:import [iapetos.registry IapetosRegistry]))
12+
13+
(defn- all-collectors
14+
[^IapetosRegistry registry]
15+
(for [[_namespace vs] (.-collectors registry)
16+
[_subsystem vs] vs
17+
[_name collector] vs]
18+
collector))
19+
20+
(defn- path-cache
21+
[^IapetosRegistry registry]
22+
(::c/path-cache (meta (.-collectors registry))))
23+
24+
(defspec t-registry-should-cache-the-path-of-registered-collectors 50
25+
(prop/for-all
26+
[registry (gen/return (prometheus/collector-registry))
27+
collector-constructor g/collector-constructor
28+
collector-name g/metric]
29+
(let [collector (collector-constructor collector-name)
30+
registry (prometheus/register registry collector)
31+
cache (path-cache registry)]
32+
(is (every? (fn [{:keys [path cache-key] :as _collector}]
33+
(= path (get cache cache-key)))
34+
(all-collectors registry))))))
35+
36+
(defspec t-registry-should-evict-path-from-cache-for-unregistered-collectors 50
37+
(prop/for-all
38+
[registry (gen/return (prometheus/collector-registry))
39+
collector-constructor g/collector-constructor
40+
collector-name g/metric]
41+
(let [collector (collector-constructor collector-name)
42+
registry (-> registry
43+
(prometheus/register collector)
44+
(prometheus/unregister collector))]
45+
(is (empty? (path-cache registry))))))

0 commit comments

Comments
 (0)