Skip to content
Snippets Groups Projects
Unverified Commit 2ec92822 authored by Antoine Rey's avatar Antoine Rey
Browse files

Merge branch 'master' into feature/Greenwich

# Conflicts:
#	pom.xml
parents c86d510e 65f2c972
No related branches found
No related tags found
No related merge requests found
Showing
with 1440 additions and 81 deletions
...@@ -6,7 +6,7 @@ This microservices branch was initially derived from [AngularJS version](https:/ ...@@ -6,7 +6,7 @@ This microservices branch was initially derived from [AngularJS version](https:/
## Starting services locally without Docker ## Starting services locally without Docker
Every microservice is a Spring Boot application and can be started locally using IDE or `../mvnw spring-boot:run` command. Please note that supporting services (Config and Discovery Server) must be started before any other application (Customers, Vets, Visits and API). Every microservice is a Spring Boot application and can be started locally using IDE or `../mvnw spring-boot:run` command. Please note that supporting services (Config and Discovery Server) must be started before any other application (Customers, Vets, Visits and API).
Tracing server and Admin server startup is optional. Startup of Tracing server, Admin server, Grafana and Prometheus is optional.
If everything goes well, you can access the following services at given location: If everything goes well, you can access the following services at given location:
* Discovery Server - http://localhost:8761 * Discovery Server - http://localhost:8761
* Config Server - http://localhost:8888 * Config Server - http://localhost:8888
...@@ -14,6 +14,8 @@ If everything goes well, you can access the following services at given location ...@@ -14,6 +14,8 @@ If everything goes well, you can access the following services at given location
* Customers, Vets and Visits Services - random port, check Eureka Dashboard * Customers, Vets and Visits Services - random port, check Eureka Dashboard
* Tracing Server (Zipkin) - http://localhost:9411/zipkin/ (we use [openzipkin](https://github.com/openzipkin/zipkin/tree/master/zipkin-server)) * Tracing Server (Zipkin) - http://localhost:9411/zipkin/ (we use [openzipkin](https://github.com/openzipkin/zipkin/tree/master/zipkin-server))
* Admin Server (Spring Boot Admin) - http://localhost:9090 * Admin Server (Spring Boot Admin) - http://localhost:9090
* Grafana Dashboards - http://localhost:3000
* Prometheus - http://localhost:9091
* Hystrix Dashboard for Circuit Breaker pattern - http://localhost:7979 - On the home page is a form where you can enter * Hystrix Dashboard for Circuit Breaker pattern - http://localhost:7979 - On the home page is a form where you can enter
the URL for an event stream to monitor, for example the `api-gateway` service running locally: `http://localhost:8080/actuator/hystrix.stream` the URL for an event stream to monitor, for example the `api-gateway` service running locally: `http://localhost:8080/actuator/hystrix.stream`
or running into docker: `http://api-gateway:8080/actuator/hystrix.stream` or running into docker: `http://api-gateway:8080/actuator/hystrix.stream`
...@@ -87,29 +89,36 @@ the host and port of your MySQL JDBC connection string. ...@@ -87,29 +89,36 @@ the host and port of your MySQL JDBC connection string.
## Custom metrics monitoring ## 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.
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. A JMeter load testing script is available to stress the application and generate metrics: [petclinic_test_plan.jmx](spring-petclinic-api-gateway/src/test/jmeter/petclinic_test_plan.jmx)
![Grafana metrics dashboard](docs/grafana-custom-metrics-dashboard.png)
### Using Prometheus ### Using Prometheus
* Prometheus can be accessed from your local machine at http://localhost:9091 * Prometheus can be accessed from your local machine at [http://localhost:9091]()
### Using Grafana with Prometheus ### 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. * An anonymous access and a Prometheus datasource are setup.
* Setup a prometheus datasource and point the URL to `http://prometheus-server:9090`, leave all the other options set to their default. * A `Spring Petclinic Metrics` Dashboard is available at the URL [http://localhost:3000/d/69JXeR0iw/spring-petclinic-metrics]().
* Add the [Micrometer/SpringBoot dashboard](https://grafana.com/dashboards/4701) via the Import Dashboard menu item. The id for the dashboard is `4701` You will find the JSON configuration file here: [docker/grafana/dashboards/grafana-petclinic-dashboard.json]().
* You may create your own dashboard or import the [Micrometer/SpringBoot dashboard](https://grafana.com/dashboards/4701) via the Import Dashboard menu item.
The id for this dashboard is `4701`.
### Custom metrics
### Custom metrics implementation Spring Boot registers a lot number of core metrics: JVM, CPU, Tomcat, Logback...
The Spring Boot auto-configuration enables the instrumentation of requests handled by Spring MVC.
All those three REST controllers `OwnerResource`, `PetResource` and `VisitResource` have been instrumented by the `@Timed` Micrometer annotation at class level.
* `customers-service` application has the following custom metrics enabled: * `customers-service` application has the following custom metrics enabled:
* counter: `create.owner` * @Timed: `petclinic.owner`
* counter: `update.owner` * @Timed: `petclinic.pet`
* counter: `create.pet`
* counter: `update.pet`
* `visits-service` application has the following custom metrics enabled: * `visits-service` application has the following custom metrics enabled:
* counter: `create.visit` * @Timed: `petclinic.visit`
## Looking for something in particular? ## Looking for something in particular?
...@@ -119,8 +128,8 @@ Grafana and Prometheus are included in the `docker-compose.yml` configuration, a ...@@ -119,8 +128,8 @@ Grafana and Prometheus are included in the `docker-compose.yml` configuration, a
| 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) | | 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) | | 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) | | 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 | | Circuit Breaker | [Hystrix fallback method](spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/VisitsServiceClient.java) |
| Grafana / Prometheus Monitoring | [Micrometer implementation](https://micrometer.io/) | | Grafana / Prometheus Monitoring | [Micrometer implementation](https://micrometer.io/), [Spring Boot Actuator Production Ready Metrics] |
Front-end module | Files | Front-end module | Files |
|-------------------|-------| |-------------------|-------|
...@@ -149,3 +158,4 @@ For pull requests, editor preferences are available in the [editor config](.edit ...@@ -149,3 +158,4 @@ For pull requests, editor preferences are available in the [editor config](.edit
[Configuration repository]: https://github.com/spring-petclinic/spring-petclinic-microservices-config [Configuration repository]: https://github.com/spring-petclinic/spring-petclinic-microservices-config
[Spring Boot Actuator Production Ready Metrics]: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html
version: '2' version: '2'
volumes:
graf-data:
services: services:
config-server: config-server:
image: mszarlinski/spring-petclinic-config-server image: mszarlinski/spring-petclinic-config-server
...@@ -99,17 +96,14 @@ services: ...@@ -99,17 +96,14 @@ services:
## Grafana / Prometheus ## Grafana / Prometheus
grafana-server: grafana-server:
image: grafana/grafana:5.2.4 build: ./docker/grafana
container_name: grafana-server container_name: grafana-server
mem_limit: 256M mem_limit: 256M
ports: ports:
- 3000:3000 - 3000:3000
volumes:
- graf-data:/var/lib/grafana
prometheus-server: prometheus-server:
build: ./docker/prometheus build: ./docker/prometheus
image: prometheus-local:v2.4.2
container_name: prometheus-server container_name: prometheus-server
mem_limit: 256M mem_limit: 256M
ports: ports:
......
FROM grafana/grafana:5.2.4
ADD ./provisioning /etc/grafana/provisioning
ADD ./grafana.ini /etc/grafana/grafana.ini
ADD ./dashboards /var/lib/grafana/dashboards
{
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "5.0.0"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": "5.0.0"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "5.0.0"
},
{
"type": "panel",
"id": "singlestat",
"name": "Singlestat",
"version": "5.0.0"
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": null,
"iteration": 1539967676482,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"id": 11,
"legend": {
"avg": false,
"current": true,
"max": false,
"min": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(rate(http_server_requests_seconds_sum{status!~\"5..\"}[1m]))/sum(rate(http_server_requests_seconds_count{ status!~\"5..\"}[1m]))",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "HTTP - AVG",
"refId": "A"
},
{
"expr": "max(http_server_requests_seconds_max{status!~\"5..\"})",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "HTTP - MAX",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "HTTP Request Latency",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"decimals": null,
"format": "s",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 0
},
"id": 9,
"legend": {
"avg": false,
"current": true,
"max": true,
"min": false,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 0.5,
"points": true,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(rate(http_server_requests_seconds_count[1m]))",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "request - ok",
"refId": "A"
},
{
"expr": "sum(rate(http_server_requests_seconds_count{status=~\"5..\"}[1m]))",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "request - err",
"refId": "B"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "HTTP Request Activity",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "ops",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 6,
"x": 0,
"y": 9
},
"id": 2,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "sum(petclinic_owner_seconds_count{method=\"PUT\", status=\"200\"})",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": "",
"title": "Owners Updated",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 6,
"x": 6,
"y": 9
},
"id": 3,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "sum(petclinic_owner_seconds_count{method=\"POST\", status=\"201\"})",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "",
"title": "Owners Created",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 6,
"x": 12,
"y": 9
},
"id": 4,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "sum(petclinic_pet_seconds_count{method=\"POST\", status=\"204\"})",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "",
"title": "Pets Created",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "Prometheus",
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 5,
"w": 6,
"x": 18,
"y": 9
},
"id": 5,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "Value",
"targets": [
{
"expr": "sum(petclinic_visit_seconds_count{method=\"POST\", status=\"204\"})",
"format": "time_series",
"instant": true,
"intervalFactor": 1,
"legendFormat": "",
"refId": "A"
}
],
"thresholds": "",
"title": "Visit Created",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"aliasColors": {},
"bars": true,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 14
},
"id": 7,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"hideEmpty": false,
"hideZero": true,
"max": true,
"min": false,
"rightSide": false,
"show": true,
"total": false,
"values": true
},
"lines": false,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": true,
"steppedLine": false,
"targets": [
{
"expr": "sum(petclinic_owner_seconds_count{method=\"POST\", status=\"201\"})",
"format": "time_series",
"instant": false,
"intervalFactor": 1,
"legendFormat": "owner create",
"refId": "A"
},
{
"expr": "sum(petclinic_pet_seconds_count{method=\"POST\", status=\"204\"})",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "pet create",
"refId": "B"
},
{
"expr": "sum(petclinic_visit_seconds_count{method=\"POST\", status=\"204\"})",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "visit create",
"refId": "C"
},
{
"expr": "sum(petclinic_owner_seconds_count{method=\"PUT\", status=\"200\"})",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "owner update",
"refId": "D"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "SPC Business Histogram",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"refresh": "30s",
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"auto": true,
"auto_count": 1,
"auto_min": "10s",
"current": {
"text": "auto",
"value": "$__auto_interval_timeRange"
},
"hide": 0,
"label": null,
"name": "timeRange",
"options": [
{
"selected": true,
"text": "auto",
"value": "$__auto_interval_timeRange"
},
{
"selected": false,
"text": "1m",
"value": "1m"
},
{
"selected": false,
"text": "10m",
"value": "10m"
},
{
"selected": false,
"text": "30m",
"value": "30m"
},
{
"selected": false,
"text": "1h",
"value": "1h"
},
{
"selected": false,
"text": "6h",
"value": "6h"
},
{
"selected": false,
"text": "12h",
"value": "12h"
},
{
"selected": false,
"text": "1d",
"value": "1d"
},
{
"selected": false,
"text": "7d",
"value": "7d"
},
{
"selected": false,
"text": "14d",
"value": "14d"
},
{
"selected": false,
"text": "30d",
"value": "30d"
}
],
"query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d",
"refresh": 2,
"type": "interval"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Spring Petclinic Metrics",
"uid": "69JXeR0iw",
"version": 1
}
##################### Spring Petclinic Microservices Grafana Configuration #####################
# possible values : production, development
app_mode = development
#################################### Paths ####################################
[paths]
# folder that contains provisioning config files that grafana will apply on startup and while running.
provisioning = /etc/grafana/provisioning
#################################### Server ####################################
[server]
# enable gzip
enable_gzip = true
#################################### Anonymous Auth ##########################
# Anonymous authentication has been enabled in the Petclinic sample with Admin role
# Do not do that in Production environment
[auth.anonymous]
# enable anonymous access
enabled = true
# specify organization name that should be used for unauthenticated users
org_name = Main Org.
# specify role for unauthenticated users
org_role = Admin
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10 #how often Grafana will scan for changed dashboards
options:
path: /var/lib/grafana/dashboards
# config file version
apiVersion: 1
# list of datasources to insert/update depending what's available in the database
datasources:
- name: Prometheus
type: prometheus
access: proxy
org_id: 1
url: http://prometheus-server:9090
is_default: true
version: 1
editable: true
docs/grafana-custom-metrics-dashboard.png

158 KiB

...@@ -71,18 +71,6 @@ ...@@ -71,18 +71,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </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> </dependencies>
</dependencyManagement> </dependencyManagement>
......
...@@ -87,10 +87,6 @@ ...@@ -87,10 +87,6 @@
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.micrometer</groupId> <groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId> <artifactId>micrometer-registry-prometheus</artifactId>
......
This diff is collapsed.
...@@ -77,10 +77,6 @@ ...@@ -77,10 +77,6 @@
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.micrometer</groupId> <groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId> <artifactId>micrometer-registry-prometheus</artifactId>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package org.springframework.samples.petclinic.customers.web; package org.springframework.samples.petclinic.customers.web;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
...@@ -36,21 +36,20 @@ import java.util.Optional; ...@@ -36,21 +36,20 @@ import java.util.Optional;
*/ */
@RequestMapping("/owners") @RequestMapping("/owners")
@RestController @RestController
@Timed("petclinic.owner")
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
class OwnerResource { class OwnerResource {
private final OwnerRepository ownerRepository; private final OwnerRepository ownerRepository;
private final MeterRegistry registry;
/** /**
* Create Owner * Create Owner
*/ */
@PostMapping @PostMapping
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public void createOwner(@Valid @RequestBody Owner owner) { public Owner createOwner(@Valid @RequestBody Owner owner) {
registry.counter("create.owner").increment(); return ownerRepository.save(owner);
ownerRepository.save(owner);
} }
/** /**
...@@ -73,7 +72,8 @@ class OwnerResource { ...@@ -73,7 +72,8 @@ class OwnerResource {
* Update Owner * Update Owner
*/ */
@PutMapping(value = "/{ownerId}") @PutMapping(value = "/{ownerId}")
public Owner updateOwner(@PathVariable("ownerId") int ownerId, @Valid @RequestBody Owner ownerRequest) { @ResponseStatus(HttpStatus.NO_CONTENT)
public void updateOwner(@PathVariable("ownerId") int ownerId, @Valid @RequestBody Owner ownerRequest) {
final Optional<Owner> owner = ownerRepository.findById(ownerId); final Optional<Owner> owner = ownerRepository.findById(ownerId);
final Owner ownerModel = owner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found")); final Owner ownerModel = owner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found"));
...@@ -84,7 +84,6 @@ class OwnerResource { ...@@ -84,7 +84,6 @@ class OwnerResource {
ownerModel.setAddress(ownerRequest.getAddress()); ownerModel.setAddress(ownerRequest.getAddress());
ownerModel.setTelephone(ownerRequest.getTelephone()); ownerModel.setTelephone(ownerRequest.getTelephone());
log.info("Saving owner {}", ownerModel); log.info("Saving owner {}", ownerModel);
registry.counter("update.owner").increment(); ownerRepository.save(ownerModel);
return ownerRepository.save(ownerModel);
} }
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package org.springframework.samples.petclinic.customers.web; package org.springframework.samples.petclinic.customers.web;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
...@@ -32,13 +32,13 @@ import java.util.Optional; ...@@ -32,13 +32,13 @@ import java.util.Optional;
* @author Maciej Szarlinski * @author Maciej Szarlinski
*/ */
@RestController @RestController
@Timed("petclinic.pet")
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
class PetResource { class PetResource {
private final PetRepository petRepository; private final PetRepository petRepository;
private final OwnerRepository ownerRepository; private final OwnerRepository ownerRepository;
private final MeterRegistry registry;
@GetMapping("/petTypes") @GetMapping("/petTypes")
...@@ -47,8 +47,8 @@ class PetResource { ...@@ -47,8 +47,8 @@ class PetResource {
} }
@PostMapping("/owners/{ownerId}/pets") @PostMapping("/owners/{ownerId}/pets")
@ResponseStatus(HttpStatus.NO_CONTENT) @ResponseStatus(HttpStatus.CREATED)
public void processCreationForm( public Pet processCreationForm(
@RequestBody PetRequest petRequest, @RequestBody PetRequest petRequest,
@PathVariable("ownerId") int ownerId) { @PathVariable("ownerId") int ownerId) {
...@@ -57,8 +57,7 @@ class PetResource { ...@@ -57,8 +57,7 @@ class PetResource {
Owner owner = optionalOwner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found")); Owner owner = optionalOwner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found"));
owner.addPet(pet); owner.addPet(pet);
registry.counter("create.pet").increment(); return save(pet, petRequest);
save(pet, petRequest);
} }
@PutMapping("/owners/*/pets/{petId}") @PutMapping("/owners/*/pets/{petId}")
...@@ -66,11 +65,10 @@ class PetResource { ...@@ -66,11 +65,10 @@ class PetResource {
public void processUpdateForm(@RequestBody PetRequest petRequest) { public void processUpdateForm(@RequestBody PetRequest petRequest) {
int petId = petRequest.getId(); int petId = petRequest.getId();
Pet pet = findPetById(petId); Pet pet = findPetById(petId);
registry.counter("update.pet").increment();
save(pet, petRequest); save(pet, petRequest);
} }
private void save(final Pet pet, final PetRequest petRequest) { private Pet save(final Pet pet, final PetRequest petRequest) {
pet.setName(petRequest.getName()); pet.setName(petRequest.getName());
pet.setBirthDate(petRequest.getBirthDate()); pet.setBirthDate(petRequest.getBirthDate());
...@@ -79,7 +77,7 @@ class PetResource { ...@@ -79,7 +77,7 @@ class PetResource {
.ifPresent(pet::setType); .ifPresent(pet::setType);
log.info("Saving pet {}", pet); log.info("Saving pet {}", pet);
petRepository.save(pet); return petRepository.save(pet);
} }
@GetMapping("owners/*/pets/{petId}") @GetMapping("owners/*/pets/{petId}")
......
...@@ -2,7 +2,6 @@ package org.springframework.samples.petclinic.customers.web; ...@@ -2,7 +2,6 @@ package org.springframework.samples.petclinic.customers.web;
import java.util.Optional; import java.util.Optional;
import io.micrometer.core.instrument.MeterRegistry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -42,9 +41,6 @@ class PetResourceTest { ...@@ -42,9 +41,6 @@ class PetResourceTest {
@MockBean @MockBean
OwnerRepository ownerRepository; OwnerRepository ownerRepository;
@MockBean
MeterRegistry registry;
@Test @Test
void shouldGetAPetInJSonFormat() throws Exception { void shouldGetAPetInJSonFormat() throws Exception {
......
...@@ -93,10 +93,6 @@ ...@@ -93,10 +93,6 @@
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.micrometer</groupId> <groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId> <artifactId>micrometer-registry-prometheus</artifactId>
......
...@@ -76,10 +76,6 @@ ...@@ -76,10 +76,6 @@
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.micrometer</groupId> <groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId> <artifactId>micrometer-registry-prometheus</artifactId>
......
...@@ -18,7 +18,7 @@ package org.springframework.samples.petclinic.visits.web; ...@@ -18,7 +18,7 @@ package org.springframework.samples.petclinic.visits.web;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Value; import lombok.Value;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -43,21 +43,20 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -43,21 +43,20 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
@Timed("petclinic.visit")
class VisitResource { class VisitResource {
private final VisitRepository visitRepository; private final VisitRepository visitRepository;
private final MeterRegistry registry;
@PostMapping("owners/*/pets/{petId}/visits") @PostMapping("owners/*/pets/{petId}/visits")
@ResponseStatus(HttpStatus.NO_CONTENT) @ResponseStatus(HttpStatus.CREATED)
void create( Visit create(
@Valid @RequestBody Visit visit, @Valid @RequestBody Visit visit,
@PathVariable("petId") int petId) { @PathVariable("petId") int petId) {
visit.setPetId(petId); visit.setPetId(petId);
log.info("Saving visit {}", visit); log.info("Saving visit {}", visit);
registry.counter("create.visit").increment(); return visitRepository.save(visit);
visitRepository.save(visit);
} }
@GetMapping("owners/*/pets/{petId}/visits") @GetMapping("owners/*/pets/{petId}/visits")
......
package org.springframework.samples.petclinic.visits.web; package org.springframework.samples.petclinic.visits.web;
import io.micrometer.core.instrument.MeterRegistry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -30,9 +29,6 @@ class VisitResourceTest { ...@@ -30,9 +29,6 @@ class VisitResourceTest {
@MockBean @MockBean
VisitRepository visitRepository; VisitRepository visitRepository;
@MockBean
MeterRegistry registry;
@Test @Test
void shouldFetchVisits() throws Exception { void shouldFetchVisits() throws Exception {
given(visitRepository.findByPetIdIn(asList(111, 222))) given(visitRepository.findByPetIdIn(asList(111, 222)))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment