Skip to content

Commit cf4469f

Browse files
committed
Initial commit
0 parents  commit cf4469f

File tree

9 files changed

+273
-0
lines changed

9 files changed

+273
-0
lines changed

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
HELP.md
2+
target/
3+
!.mvn/wrapper/maven-wrapper.jar
4+
!**/src/main/**/target/
5+
!**/src/test/**/target/
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
build/
29+
!**/src/main/**/build/
30+
!**/src/test/**/build/
31+
32+
### VS Code ###
33+
.vscode/

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# spring-boot-with-metrics
2+
3+
This demo app shows how a Spring Boot application can expose a Prometheus metrics endpoint for scraping.
4+
5+
🚼 The app was initially created with [Spring Initializr][init] and then by following the [RESTful service tutorial on spring.io][rest-tutorial].
6+
7+
To run the app:
8+
9+
mvn clean spring-boot:run
10+
11+
This will expose Prometheus metrics at `/actuator/prometheus`. This is a simple `key value` listing of metrics. You can check them out using `curl`, for example:
12+
13+
$ curl http://localhost:8080/actuator/prometheus
14+
# HELP process_uptime_seconds The uptime of the Java virtual machine
15+
# TYPE process_uptime_seconds gauge
16+
process_uptime_seconds 10.284
17+
# HELP jvm_threads_states_threads The current number of threads having NEW state
18+
# TYPE jvm_threads_states_threads gauge
19+
jvm_threads_states_threads{state="runnable",} 9.0
20+
jvm_threads_states_threads{state="blocked",} 0.0
21+
jvm_threads_states_threads{state="waiting",} 11.0
22+
...
23+
# TYPE tomcat_sessions_alive_max_seconds gauge
24+
tomcat_sessions_alive_max_seconds 0.0
25+
...
26+
27+
Once you make a request to the service at <http://localhost:8080/greeting>, you will also see a new metric exposed, `greeting_time_seconds` exposed, which shows the execution time of the `greeting` method:
28+
29+
# HELP greeting_time_seconds Time taken to return greeting
30+
# TYPE greeting_time_seconds summary
31+
greeting_time_seconds{class="com.tutorialworks.demos.springbootwithmetrics.GreetingController",exception="none",met
32+
hod="greeting",quantile="0.9",} 0.02097152
33+
greeting_time_seconds_count{class="com.tutorialworks.demos.springbootwithmetrics.GreetingController",exception="non
34+
e",method="greeting",} 1.0
35+
greeting_time_seconds_sum{class="com.tutorialworks.demos.springbootwithmetrics.GreetingController",exception="none"
36+
,method="greeting",} 0.021689345
37+
# HELP greeting_time_seconds_max Time taken to return greeting
38+
# TYPE greeting_time_seconds_max gauge
39+
greeting_time_seconds_max{class="com.tutorialworks.demos.springbootwithmetrics.GreetingController",exception="none",method="greeting",} 0.021689345
40+
41+
42+
From the [Micrometer docs][timerdocs]:
43+
44+
> All implementations of _Timer_ report at least the total time and count of events as separate time series.
45+
46+
Now we need to get these metrics into Prometheus.
47+
48+
In another terminal, use Podman to start an ephemeral Prometheus in a container, and use the `host` networking option, which will allow the container to access the Spring Boot app on `localhost`:
49+
50+
podman run --net=host \
51+
-v prometheus.yml:/etc/prometheus/prometheus.yml \
52+
prom/prometheus
53+
54+
Check the Prometheus console at <http://localhost:9090>.
55+
56+
- Go to _Targets_, you should see the Spring Boot app being scraped successfully.
57+
58+
- On the _Graph_ page, you should be able to type in a metric from the application (e.g. `tomcat_sessions_active_current_sessions`, or `greeting_time_seconds`) and see the raw data, or plot a graph
59+
60+
## Troubleshooting
61+
62+
Inside the Prometheus container, you can check that you can access the Spring Boot metrics:
63+
64+
$ podman exec -it <container-name> sh
65+
$$ wget -S -O - http://localhost:8080/actuator/prometheus
66+
67+
68+
[rest-tutorial]: https://spring.io/guides/gs/rest-service/
69+
[init]: https://start.spring.io
70+
[timerdocs]: https://micrometer.io/docs/concepts#_timers

pom.xml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>2.4.1</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.tutorialworks.demos</groupId>
12+
<artifactId>spring-boot-with-metrics</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>spring-boot-with-metrics</name>
15+
<description>Spring Boot with Metrics Demo</description>
16+
17+
<properties>
18+
<java.version>11</java.version>
19+
</properties>
20+
21+
<dependencies>
22+
<dependency>
23+
<groupId>org.springframework.boot</groupId>
24+
<artifactId>spring-boot-starter-web</artifactId>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.springframework.boot</groupId>
28+
<artifactId>spring-boot-starter-actuator</artifactId>
29+
</dependency>
30+
31+
<!-- Contains aspectj - required by TimedAspect -->
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-starter-aop</artifactId>
35+
</dependency>
36+
37+
<dependency>
38+
<groupId>io.micrometer</groupId>
39+
<artifactId>micrometer-registry-prometheus</artifactId>
40+
<scope>runtime</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.springframework.boot</groupId>
44+
<artifactId>spring-boot-starter-test</artifactId>
45+
<scope>test</scope>
46+
</dependency>
47+
</dependencies>
48+
49+
<build>
50+
<plugins>
51+
<plugin>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-maven-plugin</artifactId>
54+
</plugin>
55+
</plugins>
56+
</build>
57+
58+
</project>

prometheus.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Sample Prometheus config
2+
# This assumes that your Prometheus instance can access this application on localhost:8080
3+
4+
global:
5+
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
6+
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
7+
# scrape_timeout is set to the global default (10s).
8+
9+
scrape_configs:
10+
- job_name: 'spring boot scrape'
11+
metrics_path: '/actuator/prometheus'
12+
scrape_interval: 5s
13+
static_configs:
14+
- targets: ['localhost:8080']
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.tutorialworks.demos.springbootwithmetrics;
2+
3+
public class Greeting {
4+
5+
private final long id;
6+
private final String content;
7+
8+
public Greeting(long id, String content) {
9+
this.id = id;
10+
this.content = content;
11+
}
12+
13+
public long getId() {
14+
return id;
15+
}
16+
17+
public String getContent() {
18+
return content;
19+
}
20+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.tutorialworks.demos.springbootwithmetrics;
2+
3+
import io.micrometer.core.annotation.Timed;
4+
import io.micrometer.core.instrument.MeterRegistry;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.RequestParam;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
import java.util.concurrent.atomic.AtomicLong;
10+
11+
@RestController
12+
public class GreetingController {
13+
14+
private static final String template = "Hello, %s!";
15+
private final AtomicLong counter = new AtomicLong();
16+
17+
private final MeterRegistry registry;
18+
19+
/**
20+
* We inject the MeterRegistry into this class
21+
*/
22+
public GreetingController(MeterRegistry registry) {
23+
this.registry = registry;
24+
}
25+
26+
/**
27+
* The @Timed annotation adds timing support, so we can see how long
28+
* it takes to execute in Prometheus
29+
* percentiles
30+
*/
31+
@GetMapping("/greeting")
32+
@Timed(value = "greeting.time", description = "Time taken to return greeting",
33+
percentiles = {0.5, 0.90})
34+
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
35+
return new Greeting(counter.incrementAndGet(), String.format(template, name));
36+
}
37+
38+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.tutorialworks.demos.springbootwithmetrics;
2+
3+
import io.micrometer.core.aop.TimedAspect;
4+
import io.micrometer.core.instrument.MeterRegistry;
5+
import org.springframework.boot.SpringApplication;
6+
import org.springframework.boot.autoconfigure.SpringBootApplication;
7+
import org.springframework.context.annotation.Bean;
8+
9+
@SpringBootApplication
10+
public class SpringBootWithMetricsApplication {
11+
12+
public static void main(String[] args) {
13+
SpringApplication.run(SpringBootWithMetricsApplication.class, args);
14+
}
15+
16+
/**
17+
* This is required so that we can use the @Timed annotation
18+
* on methods that we want to time.
19+
* See: https://micrometer.io/docs/concepts#_the_timed_annotation
20+
*/
21+
@Bean
22+
public TimedAspect timedAspect(MeterRegistry registry) {
23+
return new TimedAspect(registry);
24+
}
25+
26+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
management.endpoints.web.exposure.include=health,info,prometheus
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.tutorialworks.demos.springbootwithmetrics;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.boot.test.context.SpringBootTest;
5+
6+
@SpringBootTest
7+
class SpringBootWithMetricsApplicationTests {
8+
9+
@Test
10+
void contextLoads() {
11+
}
12+
13+
}

0 commit comments

Comments
 (0)