├── .editorconfig
├── .gitignore
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── example
│ │ ├── DemoApplication.java
│ │ ├── PrometheusAutoConfiguration.java
│ │ ├── PrometheusExporter.java
│ │ ├── PrometheusMetricServices.java
│ │ └── PrometheusRegistryMetricReader.java
└── resources
│ └── application.properties
└── test
└── java
└── com
└── example
└── DemoApplicationTests.java
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | indent_style = space
7 | indent_size = 2
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Maven template
3 | target/
4 | pom.xml.tag
5 | pom.xml.releaseBackup
6 | pom.xml.versionsBackup
7 | pom.xml.next
8 | release.properties
9 | dependency-reduced-pom.xml
10 | buildNumber.properties
11 | .mvn/timing.properties
12 | ### JetBrains template
13 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
14 |
15 | *.iml
16 |
17 | ## Directory-based project format:
18 | .idea/
19 | # if you remove the above rule, at least ignore the following:
20 |
21 | # User-specific stuff:
22 | # .idea/workspace.xml
23 | # .idea/tasks.xml
24 | # .idea/dictionaries
25 |
26 | # Sensitive or high-churn files:
27 | # .idea/dataSources.ids
28 | # .idea/dataSources.xml
29 | # .idea/sqlDataSources.xml
30 | # .idea/dynamic.xml
31 | # .idea/uiDesigner.xml
32 |
33 | # Gradle:
34 | # .idea/gradle.xml
35 | # .idea/libraries
36 |
37 | # Mongo Explorer plugin:
38 | # .idea/mongoSettings.xml
39 |
40 | ## File-based project format:
41 | *.ipr
42 | *.iws
43 |
44 | ## Plugin-specific files:
45 |
46 | # IntelliJ
47 | /out/
48 |
49 | # mpeltonen/sbt-idea plugin
50 | .idea_modules/
51 |
52 | # JIRA plugin
53 | atlassian-ide-plugin.xml
54 |
55 | # Crashlytics plugin (for Android Studio and IntelliJ)
56 | com_crashlytics_export_strings.xml
57 | crashlytics.properties
58 | crashlytics-build.properties
59 |
60 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | io.fabric8.springboot
7 | prometheus
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | Spring Boot Prometheus Exporter
12 | Spring Boot Prometheus Exporter
13 |
14 |
15 | UTF-8
16 | 1.8
17 | UTF-8
18 | UTF-8
19 | ${java.version}
20 | ${java.version}
21 |
22 |
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-parent
28 | 1.3.0.RC1
29 | pom
30 | import
31 |
32 |
33 |
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-actuator
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-web
43 |
44 |
45 |
46 | io.prometheus
47 | simpleclient_servlet
48 | 0.0.11
49 |
50 |
51 | io.prometheus
52 | simpleclient_hotspot
53 | 0.0.11
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-test
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.springframework.boot
67 | spring-boot-maven-plugin
68 |
69 |
70 |
71 |
72 |
73 |
74 | spring-snapshots
75 | Spring Snapshots
76 | https://repo.spring.io/snapshot
77 |
78 | true
79 |
80 |
81 |
82 | spring-milestones
83 | Spring Milestones
84 | https://repo.spring.io/milestone
85 |
86 | false
87 |
88 |
89 |
90 |
91 |
92 | spring-snapshots
93 | Spring Snapshots
94 | https://repo.spring.io/snapshot
95 |
96 | true
97 |
98 |
99 |
100 | spring-milestones
101 | Spring Milestones
102 | https://repo.spring.io/milestone
103 |
104 | false
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/main/java/com/example/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class DemoApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(DemoApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/example/PrometheusAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import io.prometheus.client.CollectorRegistry;
4 | import io.prometheus.client.exporter.MetricsServlet;
5 | import org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration;
6 | import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
7 | import org.springframework.boot.actuate.metrics.CounterService;
8 | import org.springframework.boot.actuate.metrics.GaugeService;
9 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
12 | import org.springframework.boot.context.embedded.ServletRegistrationBean;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.Configuration;
15 |
16 | @Configuration
17 | @ConditionalOnClass(CollectorRegistry.class)
18 | @AutoConfigureBefore(MetricRepositoryAutoConfiguration.class)
19 | public class PrometheusAutoConfiguration {
20 |
21 | @Bean
22 | @ConditionalOnMissingBean
23 | public CollectorRegistry metricRegistry() {
24 | return new CollectorRegistry();
25 | }
26 |
27 | @Bean
28 | @ConditionalOnMissingBean({PrometheusMetricServices.class, CounterService.class, GaugeService.class})
29 | public PrometheusMetricServices prometheusMetricServices(CollectorRegistry metricRegistry) {
30 | return new PrometheusMetricServices(metricRegistry);
31 | }
32 |
33 | @Bean
34 | public MetricReaderPublicMetrics prometheusPublicMetrics(CollectorRegistry metricRegistry) {
35 | PrometheusRegistryMetricReader reader = new PrometheusRegistryMetricReader(metricRegistry);
36 | return new MetricReaderPublicMetrics(reader);
37 | }
38 |
39 | @Bean
40 | public ServletRegistrationBean registerPrometheusExporterServlet(CollectorRegistry metricRegistry) {
41 | return new ServletRegistrationBean(new MetricsServlet(metricRegistry), "/prometheus");
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/example/PrometheusExporter.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | public class PrometheusExporter {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/com/example/PrometheusMetricServices.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import io.prometheus.client.CollectorRegistry;
4 | import io.prometheus.client.Gauge;
5 | import io.prometheus.client.hotspot.GarbageCollectorExports;
6 | import io.prometheus.client.hotspot.MemoryPoolsExports;
7 | import io.prometheus.client.hotspot.StandardExports;
8 | import org.springframework.boot.actuate.metrics.CounterService;
9 | import org.springframework.boot.actuate.metrics.GaugeService;
10 |
11 | import java.util.concurrent.ConcurrentHashMap;
12 | import java.util.concurrent.ConcurrentMap;
13 |
14 | public class PrometheusMetricServices implements CounterService, GaugeService {
15 |
16 | private final CollectorRegistry registry;
17 |
18 | private final ConcurrentMap gauges = new ConcurrentHashMap<>();
19 |
20 | public PrometheusMetricServices(CollectorRegistry registry) {
21 | this.registry = registry;
22 | new StandardExports().register(registry);
23 | new MemoryPoolsExports().register(registry);
24 | new GarbageCollectorExports().register(registry);
25 | }
26 |
27 | @Override
28 | public void increment(String name) {
29 | getOrRegisterGauge(name).inc();
30 | }
31 |
32 | @Override
33 | public void decrement(String name) {
34 | getOrRegisterGauge(name).dec();
35 | }
36 |
37 | private Gauge getOrRegisterGauge(String name) {
38 | return gauges.computeIfAbsent(name, k -> {
39 | Gauge gauge = Gauge.build().name(sanitizeName(k)).help(k).create();
40 | registry.register(gauge);
41 | return gauge;
42 | });
43 | }
44 |
45 | @Override
46 | public void submit(String name, double value) {
47 | getOrRegisterGauge(name).set(value);
48 | }
49 |
50 | @Override
51 | public void reset(String name) {
52 | gauges.computeIfPresent(name, (k, v) -> {
53 | v.set(0);
54 | return v;
55 | });
56 | }
57 |
58 | private String sanitizeName(String name) {
59 | return name.replaceAll("[^a-zA-Z0-9_]", "_");
60 | }
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/src/main/java/com/example/PrometheusRegistryMetricReader.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import io.prometheus.client.Collector;
4 | import io.prometheus.client.CollectorRegistry;
5 | import org.springframework.boot.actuate.metrics.Metric;
6 | import org.springframework.boot.actuate.metrics.reader.MetricReader;
7 |
8 | import java.util.Collections;
9 | import java.util.HashSet;
10 | import java.util.Iterator;
11 | import java.util.Set;
12 |
13 | public class PrometheusRegistryMetricReader implements MetricReader {
14 |
15 | private final CollectorRegistry registry;
16 |
17 | public PrometheusRegistryMetricReader(CollectorRegistry registry) {
18 | this.registry = registry;
19 | }
20 |
21 |
22 | @Override
23 | public Metric> findOne(String metricName) {
24 | for (Collector.MetricFamilySamples metricFamilySamples : Collections.list(registry.metricFamilySamples())) {
25 | for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
26 | if (sample.name.equals(metricName)) {
27 | return new Metric(metricName, sample.value);
28 | }
29 | }
30 | }
31 | return null;
32 | }
33 |
34 | @Override
35 | public Iterable> findAll() {
36 | return new Iterable>() {
37 | @Override
38 | public Iterator> iterator() {
39 | Set> metrics = new HashSet>();
40 | for (Collector.MetricFamilySamples metricFamilySamples : Collections.list(registry.metricFamilySamples())) {
41 | for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
42 | metrics.add(new Metric(sample.name, sample.value));
43 | }
44 | }
45 | return metrics.iterator();
46 | }
47 | };
48 | }
49 |
50 | @Override
51 | public long count() {
52 | return Collections.list(registry.metricFamilySamples()).size();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jimmidyson/spring-boot-prometheus/b12edf22e73abe720434953890cd696c3b67049b/src/main/resources/application.properties
--------------------------------------------------------------------------------
/src/test/java/com/example/DemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 | import org.springframework.test.context.web.WebAppConfiguration;
8 |
9 | @RunWith(SpringJUnit4ClassRunner.class)
10 | @SpringApplicationConfiguration(classes = DemoApplication.class)
11 | @WebAppConfiguration
12 | public class DemoApplicationTests {
13 |
14 | @Test
15 | public void contextLoads() {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------