From 91b65515bcddc1057104c871f884af92339356d1 Mon Sep 17 00:00:00 2001 From: kevin crawley Date: Mon, 1 Oct 2018 11:55:57 -0500 Subject: [PATCH] introducing micrometer/prometheus metric collection --- README.md | 41 +++++++++++++++---- docker-compose.yml | 23 +++++++++++ docker/prometheus/Dockerfile | 2 + docker/prometheus/prometheus.yml | 32 +++++++++++++++ pom.xml | 14 +++++++ spring-petclinic-api-gateway/pom.xml | 8 ++++ spring-petclinic-customers-service/pom.xml | 8 ++++ .../customers/web/OwnerResource.java | 4 ++ .../petclinic/customers/web/PetResource.java | 6 ++- .../customers/web/PetResourceTest.java | 5 +++ spring-petclinic-vets-service/pom.xml | 8 ++++ spring-petclinic-visits-service/pom.xml | 8 ++++ .../petclinic/visits/web/VisitResource.java | 4 ++ .../visits/web/VisitResourceTest.java | 4 ++ 14 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 docker/prometheus/Dockerfile create mode 100644 docker/prometheus/prometheus.yml diff --git a/README.md b/README.md index 4057c7673..8d131ff2b 100644 --- a/README.md +++ b/README.md @@ -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 + +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. + +### 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 | |-------------------|-------| diff --git a/docker-compose.yml b/docker-compose.yml index 50efcee44..1209bd7b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,8 @@ version: '2' + +volumes: + graf-data: + services: config-server: image: mszarlinski/spring-petclinic-config-server @@ -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 diff --git a/docker/prometheus/Dockerfile b/docker/prometheus/Dockerfile new file mode 100644 index 000000000..58626f638 --- /dev/null +++ b/docker/prometheus/Dockerfile @@ -0,0 +1,2 @@ +FROM prom/prometheus:v2.4.2 +ADD prometheus.yml /etc/prometheus/ diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml new file mode 100644 index 000000000..30f089b72 --- /dev/null +++ b/docker/prometheus/prometheus.yml @@ -0,0 +1,32 @@ +# my global config +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'] diff --git a/pom.xml b/pom.xml index 72c02e268..1958e2487 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ 2.0.4.RELEASE Finchley.SR2 2.0.0.RC2 + 1.0.5 2.22.0 @@ -77,6 +78,19 @@ ${assertj.version} test + + + + io.micrometer + micrometer-core + ${micrometer.version} + + + + io.micrometer + micrometer-registry-prometheus + ${micrometer.version} + diff --git a/spring-petclinic-api-gateway/pom.xml b/spring-petclinic-api-gateway/pom.xml index 72370d2c3..ae40e34eb 100644 --- a/spring-petclinic-api-gateway/pom.xml +++ b/spring-petclinic-api-gateway/pom.xml @@ -87,6 +87,14 @@ org.projectlombok lombok + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + diff --git a/spring-petclinic-customers-service/pom.xml b/spring-petclinic-customers-service/pom.xml index 6786f8346..dc5928e47 100644 --- a/spring-petclinic-customers-service/pom.xml +++ b/spring-petclinic-customers-service/pom.xml @@ -77,6 +77,14 @@ org.projectlombok lombok + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java index da748d0fa..80916f3ef 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java @@ -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; @@ -40,6 +41,7 @@ class OwnerResource { private final OwnerRepository ownerRepository; + private final MeterRegistry registry; /** * Create Owner @@ -47,6 +49,7 @@ class OwnerResource { @PostMapping @ResponseStatus(HttpStatus.CREATED) public void createOwner(@Valid @RequestBody Owner owner) { + registry.counter("create.owner").increment(); ownerRepository.save(owner); } @@ -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); } } diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java index c657ca370..34c8c70d6 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java @@ -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; @@ -36,8 +37,9 @@ class PetResource { private final PetRepository petRepository; - private final OwnerRepository ownerRepository; + private final MeterRegistry registry; + @GetMapping("/petTypes") public List getPetTypes() { @@ -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); } @@ -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); } diff --git a/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java b/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java index 99313d23e..5b2b3303c 100644 --- a/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java +++ b/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java @@ -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; @@ -40,6 +42,9 @@ class PetResourceTest { @MockBean OwnerRepository ownerRepository; + @MockBean + MeterRegistry registry; + @Test void shouldGetAPetInJSonFormat() throws Exception { diff --git a/spring-petclinic-vets-service/pom.xml b/spring-petclinic-vets-service/pom.xml index e7705a18d..99b957703 100644 --- a/spring-petclinic-vets-service/pom.xml +++ b/spring-petclinic-vets-service/pom.xml @@ -93,6 +93,14 @@ mysql-connector-java runtime + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + diff --git a/spring-petclinic-visits-service/pom.xml b/spring-petclinic-visits-service/pom.xml index ea9184d47..c60737406 100644 --- a/spring-petclinic-visits-service/pom.xml +++ b/spring-petclinic-visits-service/pom.xml @@ -76,6 +76,14 @@ mysql-connector-java runtime + + io.micrometer + micrometer-core + + + io.micrometer + micrometer-registry-prometheus + diff --git a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java index 2ebab12e1..5905f3715 100644 --- a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java +++ b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java @@ -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; @@ -44,6 +46,7 @@ class VisitResource { private final VisitRepository visitRepository; + private final MeterRegistry registry; @PostMapping("owners/*/pets/{petId}/visits") @ResponseStatus(HttpStatus.NO_CONTENT) @@ -53,6 +56,7 @@ void create( visit.setPetId(petId); log.info("Saving visit {}", visit); + registry.counter("create.visit").increment(); visitRepository.save(visit); } diff --git a/spring-petclinic-visits-service/src/test/java/org/springframework/samples/petclinic/visits/web/VisitResourceTest.java b/spring-petclinic-visits-service/src/test/java/org/springframework/samples/petclinic/visits/web/VisitResourceTest.java index 25d33f24b..3409b30ab 100644 --- a/spring-petclinic-visits-service/src/test/java/org/springframework/samples/petclinic/visits/web/VisitResourceTest.java +++ b/spring-petclinic-visits-service/src/test/java/org/springframework/samples/petclinic/visits/web/VisitResourceTest.java @@ -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; @@ -29,6 +30,9 @@ class VisitResourceTest { @MockBean VisitRepository visitRepository; + @MockBean + MeterRegistry registry; + @Test void shouldFetchVisits() throws Exception { given(visitRepository.findByPetIdIn(asList(111, 222)))