Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing micrometer/prometheus metric collection #105

Merged
merged 1 commit into from
Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,42 @@ ENV SPRING_PROFILES_ACTIVE docker,mysql
In the `mysql section` of the `application.yml` from the [Configuration repository], you have to change
the host and port of your MySQL JDBC connection string.

## Custom metrics monitoring

@todo Add default custom dashboards to grafana
Copy link
Member

@arey arey Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe in a docs/ folder or a gh-pages branch?
I have also to reupload the Spring Petcilinic screenshot of thr readme.md. The link is broken: https://cloud.githubusercontent.com/assets/838318/19653851/61c1986a-9a16-11e6-8b94-03fd7f775bb3.png

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, screenshots of the default dashboard setup in the meantime until the custom metrics dashboard can be built out and included in a custom image build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For information, docs/ folder has been introduced in the PR #106


Grafana and Prometheus are included in the `docker-compose.yml` configuration, and the public facing applications have been instrumented with [MicroMeter](https://micrometer.io) to collect JVM and custom business metrics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For development, does the application work if Grafana and Prometheus are not started?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no dependency on those services at runtime. This implementation produces an additional endpoint on the actuator which is scraped by prometheus.


### Using Prometheus

* Prometheus can be accessed from your local machine at http://localhost:9091

### Using Grafana with Prometheus

* Login to Grafana at http://localhost:3000, the default user/pass is `admin:admin`, you will be prompted to change your password.
* Setup a prometheus datasource and point the URL to `http://prometheus-server:9090`, leave all the other options set to their default.
* Add the [Micrometer/SpringBoot dashboard](https://grafana.com/dashboards/4701) via the Import Dashboard menu item. The id for the dashboard is `4701`

### Custom metrics implementation

* `customers-service` application has the following custom metrics enabled:
* counter: `create.owner`
* counter: `update.owner`
* counter: `create.pet`
* counter: `update.pet`
* `visits-service` application has the following custom metrics enabled:
* counter: `create.visit`

## Looking for something in particular?

| Spring Cloud components | Resources |
|-------------------------|------------|
| Configuration server | [Config server properties](spring-petclinic-config-server/src/main/resources/application.yml) and [Configuration repository] |
| Service Discovery | [Eureka server](spring-petclinic-discovery-server) and [Service discovery client](spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/VetsServiceApplication.java) |
| API Gateway | [Zuul reverse proxy](spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/ApiGatewayApplication.java) and [Routing configuration](https://github.com/spring-petclinic/spring-petclinic-microservices-config/blob/master/api-gateway.yml) |
| Docker Compose | [Spring Boot with Docker guide](https://spring.io/guides/gs/spring-boot-docker/) and [docker-compose file](docker-compose.yml) |
| Circuit Breaker | [Circuit Breaker with Hystrix guide](https://spring.io/guides/gs/circuit-breaker/) and [fallback method configuration](spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/VisitsServiceClient.java) |
| Graphite Monitoring | TBD |
| Spring Cloud components | Resources |
|---------------------------------|------------|
| Configuration server | [Config server properties](spring-petclinic-config-server/src/main/resources/application.yml) and [Configuration repository] |
| Service Discovery | [Eureka server](spring-petclinic-discovery-server) and [Service discovery client](spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/VetsServiceApplication.java) |
| API Gateway | [Zuul reverse proxy](spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/ApiGatewayApplication.java) and [Routing configuration](https://github.com/spring-petclinic/spring-petclinic-microservices-config/blob/master/api-gateway.yml) |
| Docker Compose | [Spring Boot with Docker guide](https://spring.io/guides/gs/spring-boot-docker/) and [docker-compose file](docker-compose.yml) |
| Circuit Breaker | TBD |
| Grafana / Prometheus Monitoring | [Micrometer implementation](https://micrometer.io/) |

Front-end module | Files |
|-------------------|-------|
Expand Down
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
version: '2'

volumes:
graf-data:

services:
config-server:
image: mszarlinski/spring-petclinic-config-server
Expand Down Expand Up @@ -91,3 +95,22 @@ services:
entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
ports:
- 7979:7979

## Grafana / Prometheus

grafana-server:
image: grafana/grafana:5.2.4
container_name: grafana-server
mem_limit: 256M
ports:
- 3000:3000
volumes:
- graf-data:/var/lib/grafana

prometheus-server:
build: ./docker/prometheus
image: prometheus-local:v2.4.2
container_name: prometheus-server
mem_limit: 256M
ports:
- 9091:9090
2 changes: 2 additions & 0 deletions docker/prometheus/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM prom/prometheus:v2.4.2
ADD prometheus.yml /etc/prometheus/
32 changes: 32 additions & 0 deletions docker/prometheus/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# my global config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any configuration to commit in the config git repository; https://github.com/spring-petclinic/spring-petclinic-microservices-config ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! There is. I'll fork that and create a PR for those changes.

global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']

- job_name: api-gateway
metrics_path: /actuator/prometheus
static_configs:
- targets: ['api-gateway:8080']

- job_name: customers-service
metrics_path: /actuator/prometheus
static_configs:
- targets: ['customers-service:8081']

- job_name: visits-service
metrics_path: /actuator/prometheus
static_configs:
- targets: ['visits-service:8082']

- job_name: vets-service
metrics_path: /actuator/prometheus
static_configs:
- targets: ['vets-service:8083']
14 changes: 14 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<spring-boot.version>2.0.4.RELEASE</spring-boot.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
<sleuth.version>2.0.0.RC2</sleuth.version>
<micrometer.version>1.0.5</micrometer.version>

<maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>

Expand Down Expand Up @@ -77,6 +78,19 @@
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>

<!-- Micrometer core dependency -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>${micrometer.version}</version>
</dependency>
<!-- Micrometer Prometheus registry -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
8 changes: 8 additions & 0 deletions spring-petclinic-api-gateway/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Webjars -->
<dependency>
Expand Down
8 changes: 8 additions & 0 deletions spring-petclinic-customers-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Testing -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.samples.petclinic.customers.web;

import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand All @@ -40,13 +41,15 @@
class OwnerResource {

private final OwnerRepository ownerRepository;
private final MeterRegistry registry;

/**
* Create Owner
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void createOwner(@Valid @RequestBody Owner owner) {
registry.counter("create.owner").increment();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using @Timed? If we use it instead of manually incrementing metrics, tests will be alse simplified. IMHO there is little profit in measuring number of requests - Prometheus has metrics for RPS etc.)

https://spring.io/blog/2018/03/16/micrometer-spring-boot-2-s-new-application-metrics-collector

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'm delivering the workshop today so once that's done I'll make this change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@notsureifkevin do you any time to make the change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://micrometer.io/docs/concepts#_the_code_timed_code_annotation

It's not clear to me how to use this annotation and I'm constrained for time as-is. You're welcome to use merge this PR as-is, attempt to make these modifications yourself, or drop it completely. I've rebased atop master, so it should be good to go as-is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mszarlinski I propose to merge this PR and create an issue for improvment. I could work on it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created the #120 in order to merge this PR then improve it.

ownerRepository.save(owner);
}

Expand Down Expand Up @@ -81,6 +84,7 @@ public Owner updateOwner(@PathVariable("ownerId") int ownerId, @Valid @RequestBo
ownerModel.setAddress(ownerRequest.getAddress());
ownerModel.setTelephone(ownerRequest.getTelephone());
log.info("Saving owner {}", ownerModel);
registry.counter("update.owner").increment();
return ownerRepository.save(ownerModel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.samples.petclinic.customers.web;

import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand All @@ -36,8 +37,9 @@
class PetResource {

private final PetRepository petRepository;

private final OwnerRepository ownerRepository;
private final MeterRegistry registry;


@GetMapping("/petTypes")
public List<PetType> getPetTypes() {
Expand All @@ -55,6 +57,7 @@ public void processCreationForm(
Owner owner = optionalOwner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found"));
owner.addPet(pet);

registry.counter("create.pet").increment();
save(pet, petRequest);
}

Expand All @@ -63,6 +66,7 @@ public void processCreationForm(
public void processUpdateForm(@RequestBody PetRequest petRequest) {
int petId = petRequest.getId();
Pet pet = findPetById(petId);
registry.counter("update.pet").increment();
save(pet, petRequest);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.springframework.samples.petclinic.customers.web;

import java.util.Optional;

import io.micrometer.core.instrument.MeterRegistry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -40,6 +42,9 @@ class PetResourceTest {
@MockBean
OwnerRepository ownerRepository;

@MockBean
MeterRegistry registry;

@Test
void shouldGetAPetInJSonFormat() throws Exception {

Expand Down
8 changes: 8 additions & 0 deletions spring-petclinic-vets-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Testing -->
<dependency>
Expand Down
8 changes: 8 additions & 0 deletions spring-petclinic-visits-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Testing -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.util.List;
import javax.validation.Valid;

import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -44,6 +46,7 @@
class VisitResource {

private final VisitRepository visitRepository;
private final MeterRegistry registry;

@PostMapping("owners/*/pets/{petId}/visits")
@ResponseStatus(HttpStatus.NO_CONTENT)
Expand All @@ -53,6 +56,7 @@ void create(

visit.setPetId(petId);
log.info("Saving visit {}", visit);
registry.counter("create.visit").increment();
visitRepository.save(visit);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.springframework.samples.petclinic.visits.web;

import io.micrometer.core.instrument.MeterRegistry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -29,6 +30,9 @@ class VisitResourceTest {
@MockBean
VisitRepository visitRepository;

@MockBean
MeterRegistry registry;

@Test
void shouldFetchVisits() throws Exception {
given(visitRepository.findByPetIdIn(asList(111, 222)))
Expand Down