Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a616a95
Add initial set of dependencies
jpalharini Oct 1, 2025
d4ab4ec
Use PrometheusRegistry instead of CollectorRegistry
jpalharini Oct 1, 2025
6beb905
Use new builder, create name from components
jpalharini Oct 1, 2025
f2696bb
Use new method .getPrometheusName
jpalharini Oct 1, 2025
e03dbf0
Use StatefulMetric instead of SimpleCollector
jpalharini Oct 1, 2025
ee76808
Added private generic function for start-timer
jpalharini Oct 1, 2025
07ef5a6
Updated basic set operations to use DataPoint
jpalharini Oct 1, 2025
6daa366
Ugly workaround to get values of distribution metrics
jpalharini Oct 1, 2025
f6ceaf8
Replaced workaround based on reflection
jpalharini Oct 3, 2025
56fdac9
Migrate Gauge's .setCurrentTime to semantically equivalent .set
jpalharini Oct 6, 2025
d9a7f28
Cleanup imports
jpalharini Oct 6, 2025
a869e89
Migrate sanitizeMetricName to semantically equivalent string/replace …
jpalharini Oct 6, 2025
44e6b9e
Implement reading of value for Summary
jpalharini Oct 6, 2025
7223164
Use PrometheusTextFormatWriter for exporting metrics as text
jpalharini Oct 6, 2025
03b2232
Use new implementation of PushGateway
jpalharini Oct 6, 2025
6c4ddc8
Always build metrics on instantiate
jpalharini Oct 6, 2025
ecd2038
Use ByteArrayOutputStream instead of StringWriter in export
jpalharini Oct 6, 2025
f5ca76a
Fix tests
jpalharini Oct 6, 2025
f78bd50
Changed approach for distribution values
jpalharini Oct 10, 2025
80e06bf
Workaround for JVM metrics
jpalharini Oct 10, 2025
e70dc2d
Metrics of type other than Counter cannot be suffixed with 'total'
jpalharini Oct 13, 2025
5556e07
Counter metrics are automatically suffixed with 'total'
jpalharini Oct 13, 2025
ffe7982
getCount of ClassicHistogramBucket is not cumulative
jpalharini Oct 13, 2025
4860ecd
PushGateway: fixed grouping key logic and forced text format
jpalharini Oct 13, 2025
cdbed8f
Cleanup imports and dependencies
jpalharini Oct 13, 2025
3e0fece
Remove reflection where possible
jpalharini Oct 13, 2025
6d1b242
Add a path to obtain all registered metrics
jpalharini Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
:sign-releases true}]]

:dependencies [[org.clojure/clojure "1.10.3" :scope "provided"]
[io.prometheus/simpleclient "0.12.0"]
[io.prometheus/simpleclient_common "0.12.0"]
[io.prometheus/simpleclient_pushgateway "0.12.0"]
[io.prometheus/simpleclient_hotspot "0.12.0" :scope "provided"]]
[io.prometheus/prometheus-metrics-core "1.4.1"]
[io.prometheus/prometheus-metrics-exporter-pushgateway "1.4.1"]
[io.prometheus/prometheus-metrics-exposition-textformats "1.4.1"]
[io.prometheus/prometheus-metrics-instrumentation-jvm "1.4.1" :scope "provided"]]
:profiles {:dev
{:dependencies [[org.clojure/test.check "1.1.0"]
[aleph "0.4.6"]
Expand Down
61 changes: 36 additions & 25 deletions src/iapetos/collector.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
(ns iapetos.collector
(:require [iapetos.metric :as metric])
(:import [io.prometheus.client
Collector$MetricFamilySamples
CollectorRegistry
SimpleCollector
SimpleCollector$Builder]))
(:require [clojure.string :as string]
[iapetos.metric :as metric])
(:import [io.prometheus.metrics.core.datapoints DistributionDataPoint]
[io.prometheus.metrics.core.metrics MetricWithFixedMetadata MetricWithFixedMetadata$Builder StatefulMetric]))

;; ## Protocol

Expand All @@ -31,15 +29,20 @@
[labels]
(map metric/dasherize labels))

(defn- set-labels
"Attach labels to the given `SimpleCollector` instance."
[^SimpleCollector instance labels values]
(defn ordered-labels
^"[Ljava.lang.String;"
[labels values]
(let [label->value (->> (for [[k v] values]
[(-> k metric/dasherize) v])
(into {})
(comp str))
ordered-labels (->> labels (map label->value) (into-array String))]
(.labels instance ordered-labels)))
(comp str))]
(->> labels (map label->value) (into-array String))))

(defn- set-labels
"Attach labels to the given `StatefulMetric` instance."
[^StatefulMetric instance labels values]
(let [ordered (ordered-labels labels values)]
(.labelValues instance ordered)))

;; ## Record

Expand All @@ -54,6 +57,8 @@
(pr-str subsystem)))))
(or subsystem subsystem'))

(defrecord LabeledDistributionCollector [collector ^StatefulMetric instance ^DistributionDataPoint datapoint labels])

(defrecord SimpleCollectorImpl [type
namespace
name
Expand All @@ -65,22 +70,30 @@
lazy?]
Collector
(instantiate [this registry-options]
(let [subsystem (check-subsystem this registry-options)]
(-> ^SimpleCollector$Builder
(assert (or (= type :counter)
(not (string/ends-with? name "total")))
(format "name for metrics of type %s must not end with 'total' (metric: %s)"
(clojure.core/name type) (keyword namespace name)))
(let [subsystem (check-subsystem this registry-options)
name (cond->> name
subsystem (str subsystem "_")
namespace (str namespace "_"))]
(-> ^MetricWithFixedMetadata$Builder
(builder-constructor)
(.name name)
(.namespace namespace)
(.help description)
(.labelNames (label-array labels))
(cond-> subsystem (.subsystem subsystem))
(.create))))
(.build))))
(metric [_]
{:name name
:namespace namespace})
(metric-id [_]
metric-id)
(label-instance [_ instance values]
(set-labels instance labels values)))
(label-instance [this instance values]
(let [labeled (set-labels instance labels values)]
(case type
(:histogram :summary) (->LabeledDistributionCollector this instance labeled values)
labeled))))

(defn make-simple-collector
"Create a new simple collector representation to be instantiated and
Expand Down Expand Up @@ -109,10 +122,8 @@
;; ## Implementation for Raw Collectors

(defn- raw-metric
[^io.prometheus.client.Collector v]
(if-let [n (some-> (.collect v)
^Collector$MetricFamilySamples (first)
(.name))]
[^MetricWithFixedMetadata v]
(if-let [n (.getPrometheusName v)]
(let [[a b] (.split n "_" 2)]
(if b
{:name b, :namespace a}
Expand All @@ -121,7 +132,7 @@
:namespace "raw"}))

(extend-protocol Collector
io.prometheus.client.Collector
StatefulMetric
(instantiate [this _]
this)
(metric [this]
Expand All @@ -145,4 +156,4 @@
(metric-id [_]
metric)
(label-instance [_ instance values]
(label-instance collector instance values))))
(label-instance collector instance values))))
7 changes: 2 additions & 5 deletions src/iapetos/collector/fn.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
(ns iapetos.collector.fn
(:require [iapetos.collector :as collector]
[iapetos.core :as prometheus]
[iapetos.metric :as metric]
[iapetos.collector.exceptions :as ex])
(:import [io.prometheus.client CollectorRegistry]))
(:require [iapetos.core :as prometheus]
[iapetos.collector.exceptions :as ex]))

;; ## Instrumentation

Expand Down
42 changes: 25 additions & 17 deletions src/iapetos/collector/jvm.clj
Original file line number Diff line number Diff line change
@@ -1,52 +1,60 @@
(ns iapetos.collector.jvm
(:require [iapetos.collector :as collector]
[iapetos.core :as prometheus])
(:import [io.prometheus.client
Collector
CollectorRegistry]
[io.prometheus.client.hotspot
StandardExports
MemoryPoolsExports
GarbageCollectorExports
ThreadExports]))
(:import [io.prometheus.metrics.instrumentation.jvm
JvmGarbageCollectorMetrics
JvmMemoryMetrics
JvmThreadsMetrics
ProcessMetrics]))

(defn jvm-collector [metric collector]
(reify collector/Collector
(instantiate [_ _]
collector)
(metric [_]
metric)
(metric-id [_]
metric)
(label-instance [_ instance _]
instance)))

;; ## Collectors

(defn standard
"A set of standard collectors for the JVM.
Can be attached to a iapetos registry using `iapetos.core/register`."
[]
(collector/named
(jvm-collector
{:namespace "iapetos_internal"
:name "jvm_standard"}
(StandardExports.)))
(ProcessMetrics/builder)))

(defn gc
"A set of GC metric collectors for the JVM.
Can be attached to a iapetos registry using `iapetos.core/register`."
[]
(collector/named
(jvm-collector
{:namespace "iapetos_internal"
:name "jvm_gc"}
(GarbageCollectorExports.)))
(JvmGarbageCollectorMetrics/builder)))

(defn memory-pools
"A set of memory usage metric collectors for the JVM.
Can be attached to a iapetos registry using `iapetos.core/register`."
[]
(collector/named
(jvm-collector
{:namespace "iapetos_internal"
:name "jvm_memory_pools"}
(MemoryPoolsExports.)))
(JvmMemoryMetrics/builder)))

(defn threads
"A set of thread usage metric collectors for the JVM.
Can be attached to a iapetos registry using `iapetos.core/register`."
[]
(collector/named
(jvm-collector
{:namespace "iapetos_internal"
:name "jvm_threads"}
(ThreadExports.)))
(JvmThreadsMetrics/builder)))

;; ## Initialize

Expand All @@ -58,4 +66,4 @@
(standard)
(gc)
(memory-pools)
(threads))))
(threads))))
4 changes: 2 additions & 2 deletions src/iapetos/collector/ring.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[iapetos.export :as export]
[iapetos.collector.exceptions :as ex]
[clojure.string :as string])
(:import [io.prometheus.client.exporter.common TextFormat]))
(:import [io.prometheus.metrics.expositionformats PrometheusTextFormatWriter]))

;; ## Note
;;
Expand Down Expand Up @@ -74,7 +74,7 @@
using the text format (version 0.0.4)."
[registry]
{:status 200
:headers {"Content-Type" TextFormat/CONTENT_TYPE_004}
:headers {"Content-Type" PrometheusTextFormatWriter/CONTENT_TYPE}
:body (export/text-format registry)})

;; ## Middlewares
Expand Down
27 changes: 9 additions & 18 deletions src/iapetos/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,10 @@
[iapetos.operations :as ops]
[iapetos.registry :as registry])
(:refer-clojure :exclude [get inc dec set])
(:import [io.prometheus.client
CollectorRegistry
Counter
Counter$Child
Histogram
Histogram$Child
Histogram$Timer
Gauge
Gauge$Child
Gauge$Timer
Summary
Summary$Builder
Summary$Child]))
(:import [io.prometheus.metrics.core.metrics Counter
Gauge
Histogram
Summary Summary$Builder]))

;; ## Registry

Expand Down Expand Up @@ -94,7 +85,7 @@
(-> (merge
{:description description}
(metric/as-map metric options))
(collector/make-simple-collector :counter #(Counter/build))))
(collector/make-simple-collector :counter #(Counter/builder))))

(defn gauge
"Create a new `Gauge` collector:
Expand All @@ -109,7 +100,7 @@
(-> (merge
{:description description}
(metric/as-map metric options))
(collector/make-simple-collector :gauge #(Gauge/build))))
(collector/make-simple-collector :gauge #(Gauge/builder))))

(defn histogram
"Create a new `Histogram` collector:
Expand All @@ -127,8 +118,8 @@
(metric/as-map metric options))
(collector/make-simple-collector
:histogram
#(cond-> (Histogram/build)
(seq buckets) (.buckets (double-array buckets))))))
#(cond-> (Histogram/builder)
(seq buckets) (.classicUpperBounds (double-array buckets))))))

(defn- add-quantile [^Summary$Builder builder [quantile error]]
(.quantile builder quantile error))
Expand All @@ -149,7 +140,7 @@
(metric/as-map metric options))
(collector/make-simple-collector
:summary
#(reduce add-quantile (Summary/build) quantiles))))
#(reduce add-quantile (Summary/builder) quantiles))))

;; ## Raw Operations

Expand Down
Loading