diff --git a/.gitignore b/.gitignore
index 2d4261e..77e25d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,5 +72,9 @@ logs/*.json
logs/*.logfmt
logs/*.gz
+### Custom user certificates ###
+docker/ca-trust/*
+
+
+LOG_FILE_IS_UNDEFINED*
-LOG_FILE_IS_UNDEFINED
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile
index 31d912d..649532f 100644
--- a/.gitpod.Dockerfile
+++ b/.gitpod.Dockerfile
@@ -2,7 +2,7 @@ FROM gitpod/workspace-full
## Install dependencies
RUN sudo apt update && \
- sudo apt install -y curl httpie jq
+ sudo apt install -y curl httpie jq dos2unix
RUN sudo gpg -k && \
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69 && \
diff --git a/.gitpod.yml b/.gitpod.yml
index 583318e..55c3a77 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,6 +1,15 @@
image:
file: .gitpod.Dockerfile
+
vscode:
extensions:
- "redhat.java"
- "vscjava.vscode-gradle@3.13.5"
+
+tasks:
+ # Download the Grafana OpenTelemetry Java agent and saves it in the instrumentation directory
+ - name: Download Grafana OpenTelemetry Java agent
+ before: mkdir -p instrumentation
+ command: curl -L https://github.com/grafana/grafana-opentelemetry-java/releases/download/v2.4.0-beta.1/grafana-opentelemetry-java.jar -o instrumentation/grafana-opentelemetry-java.jar
+ - name: Build and start all the infrastructure
+ command: docker compose up -d --build
\ No newline at end of file
diff --git a/api-gateway/build.gradle.kts b/api-gateway/build.gradle.kts
index 89a6b9f..b845968 100644
--- a/api-gateway/build.gradle.kts
+++ b/api-gateway/build.gradle.kts
@@ -1,8 +1,6 @@
-import org.springframework.boot.gradle.tasks.run.BootRun
-
plugins {
java
- id("org.springframework.boot") version "3.3.0"
+ id("org.springframework.boot") version "3.3.1"
id("io.spring.dependency-management") version "1.1.5"
}
diff --git a/api-gateway/src/main/docker/Dockerfile b/api-gateway/src/main/docker/Dockerfile
index 7088b5c..d1dbc93 100644
--- a/api-gateway/src/main/docker/Dockerfile
+++ b/api-gateway/src/main/docker/Dockerfile
@@ -1,4 +1,11 @@
FROM eclipse-temurin:21-jdk-alpine as build
+
+ENV USE_SYSTEM_CA_CERTS=1
+
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
WORKDIR /workspace/app
ENV SERVICE=api-gateway
@@ -9,11 +16,15 @@ COPY gradle gradle
COPY gradlew .
COPY settings.gradle.kts .
-RUN --mount=type=cache,target=/root/.gradle ./gradlew :${SERVICE}:clean :${SERVICE}:build -x test
+RUN --mount=type=cache,target=/root/.gradle /__cacert_entrypoint.sh ./gradlew :${SERVICE}:clean :${SERVICE}:build -x test
RUN mkdir -p ${SERVICE}/build/dependency && (cd ${SERVICE}/build/dependency && jar -xf ../libs/*-SNAPSHOT.jar)
FROM eclipse-temurin:21-jre-alpine
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
ENV SERVICE=api-gateway
ENV LOGS_DIRECTORY=/logs/
diff --git a/api-gateway/src/main/resources/application.yml b/api-gateway/src/main/resources/application.yml
index 1ecc644..687716e 100644
--- a/api-gateway/src/main/resources/application.yml
+++ b/api-gateway/src/main/resources/application.yml
@@ -23,5 +23,23 @@ spring:
uri: lb://FRAUDETECT-SERVICE
predicates:
- Path=/api/fraudetect/**
+ loadbalancer:
+ cache:
+ ttl: 1s
# refresh:
# enabled: false # AOT / Native Image does not support Spring Cloud Refresh Scope
+
+management:
+ endpoint:
+ gateway:
+ enabled: true
+ endpoints:
+ web:
+ exposure:
+ include: "*"
+ metrics:
+ distribution:
+ percentiles-histogram:
+ http:
+ server:
+ requests: true
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/logback-spring.xml b/api-gateway/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/api-gateway/src/main/resources/logback-spring.xml
+++ b/api-gateway/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/api-gateway/src/test/resources/application.yml b/api-gateway/src/test/resources/application.yml
new file mode 100644
index 0000000..9c01199
--- /dev/null
+++ b/api-gateway/src/test/resources/application.yml
@@ -0,0 +1,7 @@
+spring:
+ cloud:
+ config:
+ enabled: false
+eureka:
+ client:
+ enabled: false
diff --git a/api-gateway/src/test/resources/logback-test.xml b/api-gateway/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/api-gateway/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/compose.yml b/compose.yml
index 7d956f2..a22847d 100644
--- a/compose.yml
+++ b/compose.yml
@@ -200,9 +200,11 @@ services:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
+ volumes:
+ - ./docker/grafana/datasources:/etc/grafana/provisioning/dashboards
entrypoint:
- sh
- - -euc
+ - -xeuc
- |
mkdir -p /etc/grafana/provisioning/datasources
cat < /etc/grafana/provisioning/datasources/ds.yaml
@@ -214,9 +216,16 @@ services:
orgId: 1
url: http://loki:3100
basicAuth: false
- isDefault: false
+ isDefault: true
version: 1
- editable: false
+ editable: true
+ jsonData:
+ derivedFields:
+ - datasourceUid: tempo
+ matcherRegex: 'trace_id'
+ matcherType: 'label'
+ name: TraceID
+ urlDisplayLabel: 'View Trace'
- name: Prometheus
type: prometheus
uid: prometheus
@@ -226,24 +235,37 @@ services:
basicAuth: false
isDefault: false
version: 1
- editable: false
+ editable: true
jsonData:
httpMethod: GET
+ exemplarTraceIdDestinations:
+ - datasourceUid: tempo
+ name: TraceID
- name: Tempo
type: tempo
access: proxy
orgId: 1
url: http://tempo:3200
basicAuth: false
- isDefault: true
+ isDefault: false
version: 1
- editable: false
+ editable: true
apiVersion: 1
uid: tempo
jsonData:
httpMethod: GET
serviceMap:
datasourceUid: prometheus
+ tracesToLogsV2:
+ datasourceUid: loki
+ filterBySpanID: false
+ filterByTraceID: true
+ tags:
+ - application
+ tracesToMetrics:
+ datasourceUid: prometheus
+ tags:
+ - application
EOF
/run.sh
image: grafana/grafana:latest
diff --git a/config-server/build.gradle.kts b/config-server/build.gradle.kts
index 20e5dbf..18b5d6d 100644
--- a/config-server/build.gradle.kts
+++ b/config-server/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
java
- id("org.springframework.boot") version "3.3.0"
+ id("org.springframework.boot") version "3.3.1"
id("io.spring.dependency-management") version "1.1.5"
}
@@ -19,7 +19,6 @@ extra["springCloudVersion"] = "2023.0.2"
dependencies {
implementation("org.springframework.cloud:spring-cloud-config-server")
- implementation("org.springframework.boot:spring-boot-starter-actuator")
// Expose metrics with Micrometer using a Prometheus registry
implementation("org.springframework.boot:spring-boot-starter-actuator")
diff --git a/config-server/src/main/docker/Dockerfile b/config-server/src/main/docker/Dockerfile
index bd48aae..c13912b 100644
--- a/config-server/src/main/docker/Dockerfile
+++ b/config-server/src/main/docker/Dockerfile
@@ -1,4 +1,9 @@
FROM eclipse-temurin:21-jdk-alpine as build
+
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
WORKDIR /workspace/app
ENV SERVICE=config-server
@@ -14,6 +19,10 @@ RUN mkdir -p ${SERVICE}/build/dependency && (cd ${SERVICE}/build/dependency && j
FROM eclipse-temurin:21-jre-alpine
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
ENV SERVICE=config-server
ENV LOGS_DIRECTORY=/logs/
diff --git a/config-server/src/main/java/com/worldline/easypay/configserver/config/PrometheusRegistryConfiguration.java b/config-server/src/main/java/com/worldline/easypay/configserver/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..31f0b74
--- /dev/null
+++ b/config-server/src/main/java/com/worldline/easypay/configserver/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.configserver.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/config-server/src/main/resources/application.properties b/config-server/src/main/resources/application.properties
index b1a5d5e..883f33b 100644
--- a/config-server/src/main/resources/application.properties
+++ b/config-server/src/main/resources/application.properties
@@ -9,5 +9,6 @@ spring.cloud.config.server.native.searchLocations=classpath:/config-server
#spring.cloud.refresh.enabled=false
management.server.port=8890
+management.endpoints.web.exposure.include=*
logging.file.name=${LOGS_DIRECTORY:../logs}/${spring.application.instance:${spring.application.name:spring}}.log
\ No newline at end of file
diff --git a/config-server/src/main/resources/config-server/application.yml b/config-server/src/main/resources/config-server/application.yml
index 57db98e..158c927 100644
--- a/config-server/src/main/resources/config-server/application.yml
+++ b/config-server/src/main/resources/config-server/application.yml
@@ -28,10 +28,21 @@ eureka:
management:
security:
enabled: false
- endpoint:
+ endpoints:
web:
exposure:
include: "*"
+ metrics:
+ tags:
+ application: ${spring.application.name}
+ instance: ${spring.application.instance}
+ namespace: local
+ metrics:
+ distribution:
+ percentiles-histogram:
+ http:
+ server:
+ requests: true
logging:
level:
diff --git a/config-server/src/main/resources/logback-spring.xml b/config-server/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/config-server/src/main/resources/logback-spring.xml
+++ b/config-server/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/config-server/src/test/resources/logback-test.xml b/config-server/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/config-server/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/discovery-server/build.gradle.kts b/discovery-server/build.gradle.kts
index 12890f9..21476ac 100644
--- a/discovery-server/build.gradle.kts
+++ b/discovery-server/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
java
- id("org.springframework.boot") version "3.3.0"
+ id("org.springframework.boot") version "3.3.1"
id("io.spring.dependency-management") version "1.1.5"
}
diff --git a/discovery-server/src/main/docker/Dockerfile b/discovery-server/src/main/docker/Dockerfile
index e591489..953b093 100644
--- a/discovery-server/src/main/docker/Dockerfile
+++ b/discovery-server/src/main/docker/Dockerfile
@@ -1,4 +1,9 @@
FROM eclipse-temurin:21-jdk-alpine as build
+
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
WORKDIR /workspace/app
ENV SERVICE=discovery-server
@@ -14,6 +19,10 @@ RUN mkdir -p ${SERVICE}/build/dependency && (cd ${SERVICE}/build/dependency && j
FROM eclipse-temurin:21-jre-alpine
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
ENV SERVICE=discovery-server
ENV LOGS_DIRECTORY=/logs/
diff --git a/discovery-server/src/main/java/com/worldline/easypay/discoveryserver/config/PrometheusRegistryConfiguration.java b/discovery-server/src/main/java/com/worldline/easypay/discoveryserver/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..c1e68c5
--- /dev/null
+++ b/discovery-server/src/main/java/com/worldline/easypay/discoveryserver/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.discoveryserver.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/discovery-server/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java b/discovery-server/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
deleted file mode 100644
index d7ac5e2..0000000
--- a/discovery-server/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
-import ch.qos.logback.classic.spi.IThrowableProxy;
-
-/**
- * From: https://stackoverflow.com/a/47771943
- */
-public class CompressedStackTraceConverter extends ThrowableProxyConverter {
- @Override
- protected String throwableProxyToString(IThrowableProxy tp) {
- String original = super.throwableProxyToString(tp);
-
- // replace the new line characters with something,
- // use your own replacement value here
- return original.replaceAll("\n", " ~~ ");
- }
-}
diff --git a/discovery-server/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java b/discovery-server/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
deleted file mode 100644
index f182c9f..0000000
--- a/discovery-server/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.contrib.json.classic.JsonLayout;
-import java.util.Map;
-
-
-public class CustomJsonLayout extends JsonLayout {
-
- private static final String APPLICATION_NAME = "application";
- private static final String APPLICATION_INSTANCE = "instance";
-
- private String applicationName;
- private String applicationInstance;
-
- public CustomJsonLayout() {
- super();
- }
-
- @Override
- protected void addCustomDataToJsonMap(Map map, ILoggingEvent event) {
- add(APPLICATION_NAME, applicationName != null, applicationName, map);
- add(APPLICATION_INSTANCE, applicationInstance != null, applicationInstance, map);
- }
-
- public String getApplicationName(String applicationName) {
- return applicationName;
- }
-
- public void setApplicationName(String applicationName) {
- this.applicationName = applicationName;
- }
-
- public String getApplicationInstance(String applicationInstance) {
- return applicationInstance;
- }
-
- public void setApplicationInstance(String applicationInstance) {
- this.applicationInstance = applicationInstance;
- }
-}
\ No newline at end of file
diff --git a/discovery-server/src/main/resources/logback-spring.xml b/discovery-server/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/discovery-server/src/main/resources/logback-spring.xml
+++ b/discovery-server/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/discovery-server/src/test/java/com/worldline/easypay/discoveryserver/DiscoveryServerApplicationTests.java b/discovery-server/src/test/java/com/worldline/easypay/discoveryserver/DiscoveryServerApplicationTests.java
index caa35be..6caf9b6 100644
--- a/discovery-server/src/test/java/com/worldline/easypay/discoveryserver/DiscoveryServerApplicationTests.java
+++ b/discovery-server/src/test/java/com/worldline/easypay/discoveryserver/DiscoveryServerApplicationTests.java
@@ -3,7 +3,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-@SpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DiscoveryServerApplicationTests {
@Test
diff --git a/discovery-server/src/test/resources/application.properties b/discovery-server/src/test/resources/application.properties
new file mode 100644
index 0000000..ff97549
--- /dev/null
+++ b/discovery-server/src/test/resources/application.properties
@@ -0,0 +1,6 @@
+#eureka.client.enabled=false
+spring.cloud.config.enabled=false
+
+eureka.instance.hostname=localhost
+eureka.client.registerWithEureka=false
+eureka.client.fetchRegistry=false
\ No newline at end of file
diff --git a/discovery-server/src/test/resources/logback-test.xml b/discovery-server/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/discovery-server/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docker/alloy/config.alloy b/docker/alloy/config.alloy
index a56c006..4827a70 100644
--- a/docker/alloy/config.alloy
+++ b/docker/alloy/config.alloy
@@ -1,5 +1,5 @@
logging {
- level = "info"
+ level = "debug"
format = "logfmt"
}
@@ -30,13 +30,14 @@ loki.source.file "jsonlogfiles" {
loki.process "jsonlogs" {
forward_to = [loki.write.endpoint.receiver]
- //stage.luhn { }
+ // stage.luhn { }
stage.json {
expressions = {
// timestamp = "timestamp",
application = "context.properties.applicationName",
instance = "context.properties.instance",
+ trace_id = "mdc.trace_id",
}
}
@@ -44,6 +45,7 @@ loki.process "jsonlogs" {
values = {
application = "application",
instance = "instance",
+ trace_id = "trace_id",
}
}
@@ -78,7 +80,35 @@ otelcol.receiver.otlp "default" {
output {
metrics = [otelcol.processor.batch.default.input]
logs = [otelcol.processor.batch.default.input]
- traces = [otelcol.processor.batch.default.input]
+ traces = [otelcol.processor.tail_sampling.actuator.input]
+ }
+}
+
+otelcol.processor.tail_sampling "actuator" {
+ policy {
+ name = "filter_http_url"
+ type = "string_attribute"
+ string_attribute {
+ key = "http.url"
+ values = ["/actuator/health", "/actuator/prometheus"]
+ enabled_regex_matching = true
+ invert_match = true
+ }
+ }
+
+ policy {
+ name = "filter_url_path"
+ type = "string_attribute"
+ string_attribute {
+ key = "url.path"
+ values = ["/actuator/health", "/actuator/prometheus"]
+ enabled_regex_matching = true
+ invert_match = true
+ }
+ }
+
+ output {
+ traces = [otelcol.processor.batch.default.input]
}
}
diff --git a/docker/grafana/dashboards/jdbc.json b/docker/grafana/dashboards/jdbc.json
new file mode 100644
index 0000000..045b0dd
--- /dev/null
+++ b/docker/grafana/dashboards/jdbc.json
@@ -0,0 +1,1717 @@
+{
+ "__inputs": [
+ {
+ "name": "Prometheus",
+ "label": "Prometheus",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "prometheus",
+ "pluginName": "Prometheus"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "datasource",
+ "id": "prometheus",
+ "name": "Prometheus",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "stat",
+ "name": "Stat",
+ "version": ""
+ },
+ {
+ "type": "panel",
+ "id": "timeseries",
+ "name": "Time series",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "grafana",
+ "uid": "-- Grafana --"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "description": "Spring Boot (Micrometer) with JDBC and HikariCP.",
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 12,
+ "panels": [
+ {
+ "datasource": "Prometheus",
+ "description": "History of idle/active.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Max"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Min"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "blue",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Idle"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Active"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 0,
+ "y": 1
+ },
+ "id": 10,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "width": 80
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(jdbc_connections_active{namespace=\"$namespace\", application=\"$application\", name=\"$jdbc_connection_name\"})",
+ "legendFormat": "Active",
+ "range": true,
+ "refId": "Active"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(jdbc_connections_idle{namespace=\"$namespace\", application=\"$application\", name=\"$jdbc_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Idle",
+ "range": true,
+ "refId": "Idle"
+ }
+ ],
+ "title": "Idle / Active",
+ "type": "timeseries"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Current number of active connections that have been allocated from the data source.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 1
+ },
+ "id": 5,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "jdbc_connections_active{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", name=\"$jdbc_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Active",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Number of established but idle connections.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 5
+ },
+ "id": 4,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "jdbc_connections_idle{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", name=\"$jdbc_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Idle",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "History of min/max.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Max"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Min"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "blue",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Idle"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Active"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 0,
+ "y": 9
+ },
+ "id": 9,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "width": 80
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(jdbc_connections_max{namespace=\"$namespace\", application=\"$application\", name=\"$jdbc_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Max",
+ "range": true,
+ "refId": "Max"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(jdbc_connections_min{namespace=\"$namespace\", application=\"$application\", name=\"$jdbc_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Min",
+ "range": true,
+ "refId": "Min"
+ }
+ ],
+ "title": "Min / Max",
+ "type": "timeseries"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Maximum number of active connections that can be allocated at the same time.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 9
+ },
+ "id": 3,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "jdbc_connections_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", name=\"$jdbc_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Max",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Minimum number of idle connections in the pool.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 13
+ },
+ "id": 2,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "jdbc_connections_min{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", name=\"$jdbc_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Min",
+ "type": "stat"
+ }
+ ],
+ "repeat": "jdbc_connection_name",
+ "repeatDirection": "h",
+ "title": "JDBC: $jdbc_connection_name",
+ "type": "row"
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 1
+ },
+ "id": 7,
+ "panels": [
+ {
+ "datasource": "Prometheus",
+ "description": "History of idle/active.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Max"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Min"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "blue",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Idle"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Active"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Pending"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 0,
+ "y": 2
+ },
+ "id": 18,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "width": 80
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(hikaricp_connections_active{namespace=\"$namespace\", application=\"$application\", pool=\"$hikaricp_connection_name\"})",
+ "legendFormat": "Active",
+ "range": true,
+ "refId": "Active"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(hikaricp_connections_pending{namespace=\"$namespace\", application=\"$application\", pool=\"$hikaricp_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Pending",
+ "range": true,
+ "refId": "Pending"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(hikaricp_connections_idle{namespace=\"$namespace\", application=\"$application\", pool=\"$hikaricp_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Idle",
+ "range": true,
+ "refId": "Idle"
+ }
+ ],
+ "title": "Idle / Active / Pending",
+ "type": "timeseries"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Active connections.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 2
+ },
+ "id": 16,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_active{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Active",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Idle connections.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 6
+ },
+ "id": 15,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_idle{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Idle",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "History of min/max.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Max"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Min"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "blue",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Idle"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Active"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 0,
+ "y": 10
+ },
+ "id": 17,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "width": 80
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(hikaricp_connections_max{namespace=\"$namespace\", application=\"$application\", pool=\"$hikaricp_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Max",
+ "range": true,
+ "refId": "Max"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(hikaricp_connections_min{namespace=\"$namespace\", application=\"$application\", pool=\"$hikaricp_connection_name\"})",
+ "hide": false,
+ "legendFormat": "Min",
+ "range": true,
+ "refId": "Min"
+ }
+ ],
+ "title": "Min / Max",
+ "type": "timeseries"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Max connections.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 10
+ },
+ "id": 14,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Max",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Min connections.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 14
+ },
+ "id": 13,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_min{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Min",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "History of timeouts.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Max"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Min"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "blue",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Idle"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "yellow",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Active"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Pending"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Usage"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "red",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Creation"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "green",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 12,
+ "w": 19,
+ "x": 0,
+ "y": 18
+ },
+ "id": 21,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true,
+ "width": 80
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(irate(hikaricp_connections_usage_seconds_sum{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]) / irate(hikaricp_connections_usage_seconds_count{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]))",
+ "legendFormat": "Usage",
+ "range": true,
+ "refId": "Usage"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(irate(hikaricp_connections_acquire_seconds_sum{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]) / irate(hikaricp_connections_acquire_seconds_count{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]))",
+ "hide": false,
+ "legendFormat": "Acquire",
+ "range": true,
+ "refId": "Acquire"
+ },
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "sum(irate(hikaricp_connections_creation_seconds_sum{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]) / irate(hikaricp_connections_creation_seconds_count{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}[$__rate_interval]))",
+ "hide": false,
+ "legendFormat": "Creation",
+ "range": true,
+ "refId": "Creation"
+ }
+ ],
+ "title": "Usage / Acquire / Creation",
+ "type": "timeseries"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Max time on usage.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 18
+ },
+ "id": 27,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_usage_seconds_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Max usage",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Max time on acquiring.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 22
+ },
+ "id": 26,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_acquire_seconds_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Max acquire",
+ "type": "stat"
+ },
+ {
+ "datasource": "Prometheus",
+ "description": "Max time on creation.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 5,
+ "x": 19,
+ "y": 26
+ },
+ "id": 25,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0-68002",
+ "targets": [
+ {
+ "datasource": "Prometheus",
+ "editorMode": "code",
+ "expr": "hikaricp_connections_creation_seconds_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\", pool=\"$hikaricp_connection_name\"}",
+ "legendFormat": "{{instance}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Max creation",
+ "type": "stat"
+ }
+ ],
+ "repeat": "hikaricp_connection_name",
+ "repeatDirection": "h",
+ "title": "HikariCP: $hikaricp_connection_name",
+ "type": "row"
+ }
+ ],
+ "refresh": "",
+ "revision": 8,
+ "schemaVersion": 39,
+ "tags": [
+ "prometheus",
+ "spring-boot",
+ "micrometer",
+ "jdbc",
+ "hikaricp"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {},
+ "datasource": "Prometheus",
+ "definition": "label_values(jdbc_connections_max, namespace)",
+ "description": "Namespace in k8s.",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Namespace",
+ "multi": false,
+ "name": "namespace",
+ "options": [],
+ "query": {
+ "query": "label_values(jdbc_connections_max, namespace)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "type": "query"
+ },
+ {
+ "current": {},
+ "datasource": "Prometheus",
+ "definition": "label_values(jdbc_connections_max{namespace=\"$namespace\"}, application)",
+ "description": "Name of Spring Boot Application.",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Application",
+ "multi": false,
+ "name": "application",
+ "options": [],
+ "query": {
+ "query": "label_values(jdbc_connections_max{namespace=\"$namespace\"}, application)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "type": "query"
+ },
+ {
+ "current": {},
+ "datasource": "Prometheus",
+ "definition": "label_values(jdbc_connections_max{namespace=\"$namespace\", application=\"$application\"}, instance)",
+ "description": "Instance of application.",
+ "hide": 0,
+ "includeAll": true,
+ "label": "Instance",
+ "multi": false,
+ "name": "instance",
+ "options": [],
+ "query": {
+ "query": "label_values(jdbc_connections_max{namespace=\"$namespace\", application=\"$application\"}, instance)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "type": "query"
+ },
+ {
+ "current": {},
+ "datasource": "Prometheus",
+ "definition": "label_values(jdbc_connections_max{namespace=\"$namespace\",application=\"$application\", instance=~\"$instance\"}, name)",
+ "description": "Name of JDBC DataSource.",
+ "hide": 0,
+ "includeAll": true,
+ "label": "JDBC",
+ "multi": false,
+ "name": "jdbc_connection_name",
+ "options": [],
+ "query": {
+ "query": "label_values(jdbc_connections_max{namespace=\"$namespace\",application=\"$application\", instance=~\"$instance\"}, name)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "type": "query"
+ },
+ {
+ "current": {},
+ "datasource": "Prometheus",
+ "definition": "label_values(hikaricp_connections_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\"}, pool)",
+ "description": "Name of HikariCP.",
+ "hide": 0,
+ "includeAll": true,
+ "label": "HikariCP",
+ "multi": false,
+ "name": "hikaricp_connection_name",
+ "options": [],
+ "query": {
+ "query": "label_values(hikaricp_connections_max{namespace=\"$namespace\", application=\"$application\", instance=~\"$instance\"}, pool)",
+ "refId": "StandardVariableQuery"
+ },
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "type": "query"
+ }
+ ]
+ },
+ "time": {
+ "from": "now-30m",
+ "to": "now"
+ },
+ "timeRangeUpdatedDuringEditOrView": false,
+ "timepicker": {},
+ "timezone": "",
+ "title": "Spring Boot JDBC & HikariCP",
+ "uid": "spring-boot-jdbc-hikaricp",
+ "weekStart": "",
+ "gnetId": 20729
+ }
\ No newline at end of file
diff --git a/docker/grafana/dashboards/jvm.json b/docker/grafana/dashboards/jvm.json
new file mode 100644
index 0000000..79fd2f8
--- /dev/null
+++ b/docker/grafana/dashboards/jvm.json
@@ -0,0 +1,3767 @@
+{
+ "__inputs": [
+ {
+ "name": "DS_PROMETHEUS",
+ "label": "Prometheus",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "prometheus",
+ "pluginName": "Prometheus"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "11.0.0"
+ },
+ {
+ "type": "datasource",
+ "id": "prometheus",
+ "name": "Prometheus",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "stat",
+ "name": "Stat",
+ "version": ""
+ },
+ {
+ "type": "panel",
+ "id": "timeseries",
+ "name": "Time series",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "limit": 100,
+ "name": "Annotations & Alerts",
+ "showIn": 0,
+ "type": "dashboard"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "enable": true,
+ "expr": "resets(process_uptime_seconds{application=\"$application\", instance=~\"$instance\"}[1m]) > 0",
+ "iconColor": "rgba(255, 96, 96, 1)",
+ "name": "Restart Detection",
+ "showIn": 0,
+ "step": "1m",
+ "tagKeys": "restart-tag",
+ "textFormat": "uptime reset",
+ "titleFormat": "Restart"
+ }
+ ]
+ },
+ "description": "Dashboard for Micrometer instrumented applications (Java, Spring Boot, Micronaut)",
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "gnetId": 4701,
+ "graphTooltip": 1,
+ "id": null,
+ "links": [],
+ "panels": [
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 139,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Quick Facts",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 1,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ "id": 63,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "editorMode": "code",
+ "expr": "process_uptime_seconds{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "range": true,
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Uptime",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "dateTimeAsIso"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 6,
+ "y": 1
+ },
+ "id": 92,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "editorMode": "code",
+ "expr": "process_start_time_seconds{application=\"$application\", instance=~\"$instance\"}*1000",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "range": true,
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Start time",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 2,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)",
+ "value": null
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 70
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 12,
+ "y": 1
+ },
+ "id": 65,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "editorMode": "code",
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=~\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "range": true,
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Heap used",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 2,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ },
+ {
+ "options": {
+ "from": -1e+32,
+ "result": {
+ "text": "N/A"
+ },
+ "to": 0
+ },
+ "type": "range"
+ }
+ ],
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)",
+ "value": null
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 70
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 18,
+ "y": 1
+ },
+ "id": 75,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=~\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Non-Heap used",
+ "type": "stat"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 4
+ },
+ "id": 140,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "I/O Overview",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "ops"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 5
+ },
+ "id": 111,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=~\"$instance\"}[1m]))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "HTTP",
+ "refId": "A"
+ }
+ ],
+ "title": "Rate",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "ops"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "HTTP"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#890f02",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "HTTP - 5xx"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#bf1b00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 5
+ },
+ "id": 112,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=~\"$instance\", status=~\"5..\"}[1m]))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - 5xx",
+ "refId": "A"
+ }
+ ],
+ "title": "Errors",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 5
+ },
+ "id": 113,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_sum{application=\"$application\", instance=~\"$instance\", status!~\"5..\"}[1m]))/sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=~\"$instance\", status!~\"5..\"}[1m]))",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - AVG",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "max(http_server_requests_seconds_max{application=\"$application\", instance=~\"$instance\", status!~\"5..\"})",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - MAX",
+ "refId": "B"
+ }
+ ],
+ "title": "Duration",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 5
+ },
+ "id": 119,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "tomcat_threads_busy_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - BSY",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "tomcat_threads_current_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - CUR",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "tomcat_threads_config_max_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - MAX",
+ "refId": "C"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jetty_threads_busy{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - BSY",
+ "refId": "D"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jetty_threads_current{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - CUR",
+ "refId": "E"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jetty_threads_config_max{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - MAX",
+ "refId": "F"
+ }
+ ],
+ "title": "Utilisation",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 12
+ },
+ "id": 141,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 13
+ },
+ "id": 24,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=~\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=~\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Heap",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 13
+ },
+ "id": 25,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=~\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=~\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Non-Heap",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 13
+ },
+ "id": 26,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Total",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 13
+ },
+ "id": 86,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_memory_vss_bytes{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": true,
+ "intervalFactor": 2,
+ "legendFormat": "vss",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_memory_rss_bytes{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "rss",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_memory_swap_bytes{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "swap",
+ "refId": "C"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_memory_rss_bytes{application=\"$application\", instance=~\"$instance\"} + process_memory_swap_bytes{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "total",
+ "refId": "D"
+ }
+ ],
+ "title": "JVM Process Memory",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 20
+ },
+ "id": 142,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Misc",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "max": 1,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 21
+ },
+ "id": 106,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "system_cpu_usage{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "system",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_cpu_usage{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "process",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "avg_over_time(process_cpu_usage{application=\"$application\", instance=~\"$instance\"}[15m])",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "process-15m",
+ "refId": "C"
+ }
+ ],
+ "title": "CPU Usage",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 21
+ },
+ "id": 93,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "system_load_average_1m{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "system-1m",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "system_cpu_count{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "cpus",
+ "refId": "B"
+ }
+ ],
+ "title": "Load",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 21
+ },
+ "id": 32,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_threads_live_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "live",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_threads_daemon_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "daemon",
+ "metric": "",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_threads_peak_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "peak",
+ "refId": "C",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "process",
+ "refId": "D",
+ "step": 2400
+ }
+ ],
+ "title": "Threads",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "blocked"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#bf1b00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "new"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#fce2de",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "runnable"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#7eb26d",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "terminated"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#511749",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "timed-waiting"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#c15c17",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "waiting"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#eab839",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 21
+ },
+ "id": 124,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_threads_states_threads{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{state}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Thread States",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "description": "The percent of time spent on Garbage Collection over all CPUs assigned to the JVM process.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "max": 1,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 28
+ },
+ "id": 138,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "sum(rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=~\"$instance\"}[1m])) by (application, instance) / on(application, instance) system_cpu_count",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "CPU time spent on GC",
+ "refId": "A"
+ }
+ ],
+ "title": "GC Pressure",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "opm"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "debug"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#1F78C1",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "error"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#BF1B00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "info"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#508642",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "trace"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#6ED0E0",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "warn"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#EAB839",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 6,
+ "y": 28
+ },
+ "id": 91,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "increase(logback_events_total{application=\"$application\", instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{level}}",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "title": "Log Events",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "log": 10,
+ "type": "log"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 28
+ },
+ "id": 61,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_files_open_files{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "open",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "process_files_max_files{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "B",
+ "step": 2400
+ }
+ ],
+ "title": "File Descriptors",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 35
+ },
+ "id": 143,
+ "panels": [],
+ "repeat": "persistence_counts",
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory Pools (Heap)",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 36
+ },
+ "id": 3,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "repeat": "jvm_memory_pool_heap",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "commited",
+ "metric": "",
+ "refId": "B",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_max_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "C",
+ "step": 1800
+ }
+ ],
+ "title": "$jvm_memory_pool_heap",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 43
+ },
+ "id": 144,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory Pools (Non-Heap)",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 44
+ },
+ "id": 78,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "repeat": "jvm_memory_pool_nonheap",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "commited",
+ "metric": "",
+ "refId": "B",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_memory_max_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "C",
+ "step": 1800
+ }
+ ],
+ "title": "$jvm_memory_pool_nonheap",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 58
+ },
+ "id": 145,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Garbage Collection",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "ops"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 59
+ },
+ "id": 98,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "{{action}} ({{cause}})",
+ "refId": "A"
+ }
+ ],
+ "title": "Collections",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 59
+ },
+ "id": 101,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=~\"$instance\"}[1m])/rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "avg {{action}} ({{cause}})",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_gc_pause_seconds_max{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "max {{action}} ({{cause}})",
+ "refId": "B"
+ }
+ ],
+ "title": "Pause Durations",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "Bps"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 59
+ },
+ "id": 99,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "rate(jvm_gc_memory_allocated_bytes_total{application=\"$application\", instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "allocated",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "rate(jvm_gc_memory_promoted_bytes_total{application=\"$application\", instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "promoted",
+ "refId": "B"
+ }
+ ],
+ "title": "Allocated/Promoted",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 66
+ },
+ "id": 146,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Classloading",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 67
+ },
+ "id": 37,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_classes_loaded_classes{application=\"$application\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "loaded",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "title": "Classes loaded",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 67
+ },
+ "id": 38,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "delta(jvm_classes_loaded_classes{application=\"$application\",instance=~\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "delta-1m",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "title": "Class delta",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 74
+ },
+ "id": 147,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "tempo",
+ "uid": "tempo"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Buffer Pools",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "decbytes"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "count"
+ },
+ "properties": [
+ {
+ "id": "unit",
+ "value": "short"
+ },
+ {
+ "id": "decimals",
+ "value": 0
+ },
+ {
+ "id": "custom.axisPlacement",
+ "value": "right"
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "buffers"
+ },
+ "properties": [
+ {
+ "id": "unit",
+ "value": "short"
+ },
+ {
+ "id": "decimals",
+ "value": 0
+ },
+ {
+ "id": "custom.axisPlacement",
+ "value": "right"
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 75
+ },
+ "id": 131,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "repeat": "jvm_buffer_pool",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "capacity",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=~\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "buffers",
+ "refId": "C"
+ }
+ ],
+ "title": "$jvm_buffer_pool",
+ "type": "timeseries"
+ }
+ ],
+ "refresh": "30s",
+ "schemaVersion": 39,
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "current": {},
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "definition": "",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Application",
+ "multi": false,
+ "name": "application",
+ "options": [],
+ "query": "label_values(application)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {},
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "definition": "",
+ "hide": 0,
+ "includeAll": true,
+ "label": "Instance",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "instance",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {},
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Memory Pools Heap",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_memory_pool_heap",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"heap\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {},
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Memory Pools Non-Heap",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_memory_pool_nonheap",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=~\"$instance\", area=\"nonheap\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 2,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {},
+ "datasource": {
+ "type": "prometheus",
+ "uid": "${DS_PROMETHEUS}"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Buffer Pools",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_buffer_pool",
+ "options": [],
+ "query": "label_values(jvm_buffer_memory_used_bytes{application=\"$application\", instance=~\"$instance\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-5m",
+ "to": "now"
+ },
+ "timeRangeUpdatedDuringEditOrView": false,
+ "timepicker": {
+ "now": true,
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "browser",
+ "title": "JVM (Micrometer)",
+ "uid": "fdohhxix2m39ce",
+ "version": 5,
+ "weekStart": ""
+ }
\ No newline at end of file
diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml
index 26aa399..aac72aa 100644
--- a/docker/prometheus/prometheus.yml
+++ b/docker/prometheus/prometheus.yml
@@ -19,7 +19,7 @@ scrape_configs:
metrics_path: /actuator/prometheus
static_configs:
- targets:
- - config-server:8889
+ - config-server:8890
- job_name: prometheus-eureka-server
scrape_interval: 5s
@@ -37,29 +37,6 @@ scrape_configs:
- server: http://discovery-server:8761/eureka
refresh_interval: 5s
relabel_configs:
- - source_labels: [__meta_eureka_app_name]
- target_label: application
- source_labels: [__meta_eureka_app_instance_metadata_metrics_path]
target_label: __metrics_path__
- - source_labels: [__address__]
- target_label: instance
- # Discover targets from Eureka and probe the health endpoints via the Blackbox Exporter (Blackbox monitoring)
- # - job_name: blackbox-via-service-discovery
- # params:
- # module:
- # - http_2xx
- # scrape_interval: 15s
- # scrape_timeout: 15s
- # metrics_path: /probe
- # eureka_sd_configs:
- # - server: http://prometheus-eureka-server:8761/eureka
- # refresh_interval: 30s
- # relabel_configs:
- # - source_labels: [__meta_eureka_app_name]
- # target_label: application
- # - source_labels: [__meta_eureka_app_instance_healthcheck_url]
- # target_label: __param_target
- # - source_labels: [__address__]
- # target_label: instance
- # - target_label: __address__
- # replacement: blackbox-exporter:9115
+
diff --git a/docs/workshop.md b/docs/workshop.md
index 30f6681..fe7dd1b 100644
--- a/docs/workshop.md
+++ b/docs/workshop.md
@@ -114,9 +114,9 @@ If you use the wrapper, you won't have troubles. Otherwise...:
```jshelllanguage
$ gradle -version
- ------------------------------------------------------------
+------------------------------------------------------------
Gradle 8.7
- ------------------------------------------------------------
+------------------------------------------------------------
Build time: 2024-03-22 15:52:46 UTC
Revision: 650af14d7653aa949fce5e886e685efc9cf97c10
@@ -152,15 +152,16 @@ Duration: 0:05:00
We will assume you will use GitPod for this workshop :)
-[![Open in Gitpod](img/open-in-gitpod.svg)](https://gitpod.io/#github.com/alexandre-touret/observability-workshop.git)
+[![Open in Gitpod](img/open-in-gitpod.svg)](https://gitpod.io/#github.com/worldline/observability-workshop.git)
### Start the infrastructure
The "infrastructure stack" is composed of the following components:
* One [PostgreSQL](https://www.postgresql.org/) instance per micro service
* One [Kafka broker](https://kafka.apache.org/)
-* ONe [Service Discovery](https://spring.io/guides/gs/service-registration-and-discovery) microservice to enable load balancing & loose coupling.
+* One [Service Discovery](https://spring.io/guides/gs/service-registration-and-discovery) microservice to enable load balancing & loose coupling.
* One [Configuration server](https://docs.spring.io/spring-cloud-config/) is also used to centralise the configuration of our microservices.
+* The following microservices: API Gateway, Merchant BO, Fraud Detect, Smart Bank Gateway
To run it, execute the following command
@@ -172,9 +173,7 @@ To check if all the services are up, you can run this command:
``` bash
$ docker compose ps -a
```
-> aside negative
->
-> TODO ajouter retour commande
+And check the status of every service.
### Start the rest of our microservices
@@ -188,39 +187,12 @@ Run the following command:
$ ./gradlew :easypay-service:bootRun -x test
```
-#### The Merchant BO
-Run the following command:
-
-```bash
-$ ./gradlew :merchant-backoffice:bootRun -x test
-```
-#### The Fraud System
-Run the following command:
-
-```bash
-$ ./gradlew :frauddetect-service:bootRun -x test
-```
-
-#### The Smart Bank Gateway
-Run the following command:
-
-```bash
-$ ./gradlew :smartbank-gateway:bootRun -x test
-```
-
-#### The API Gateway
-
-Run the following command:
-
-```bash
-$ ./gradlew :api-gateway:bootRun -x test
-```
#### Validation
Open the Eureka website started during the infrastructure setup
-If you run this workshop on your desktop, you can go to this URL.
-If you run it on GitPod, you can go the corresponding URL (e.g., TODO) instead.
+If you run this workshop on your desktop, you can go to this URL: http://localhost:8761.
+If you run it on GitPod, you can go to the corresponding URL (e.g., https://8761-worldline-observability-w98vrd59k5h.ws-eu114.gitpod.io) instead.
You can now reach our platform to initiate a payment:
@@ -327,7 +299,7 @@ You should get these log entries in JSON format. Open one of these files and che
> aside positive
>
-> As you can see, the logs are not helpful for getting more information such as the business or user context.~~~~
+> As you can see, the logs are not helpful for getting more information such as the business or user context.
>
> If you want to dig into this particular topic, you can check out [this article](https://blog.worldline.tech/2020/01/22/back-to-basics-logging.html).
@@ -383,7 +355,7 @@ Modify the exception trace to provide contextual information such as the authorI
Go to the ``easypay-service/src/main/java/com/worldline/easypay/payment/control/CardValidator.java`` class and modify the following block code in the process method in the same way:
```java
- private void process(PaymentProcessingContext context) {
+private void process(PaymentProcessingContext context) {
[...]
if (!cardValidator.checkCardNumber(context.cardNumber)) {
@@ -421,9 +393,9 @@ You can go further and add as many log you think it would help in production.
You can restart your easy pay service by typing ``CTRL+C`` in your console prompt, and run the following command:
-> aside negative
->
-> TODO mettre la commande + le résultat dans les logs
+```bash
+$ ./gradlew :easypay-service:bootRun -x test
+```
Now you can run the same commands ran earlier and check again the logs.
@@ -471,12 +443,33 @@ java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()"
To find the root cause, add first a _smart_ log entry in the ``easypay-service/src/main/java/com/worldline/easypay/payment/control/PosValidator.java`` class.
In the ``isActive()`` method, catch the exception and trace the error:
-> aside negative
->
-> TODO Commande pour le message d'erreur + message d'erreur
->
-You can also prevent this issue by simply fixing the SQL import file
+```java
+public boolean isActive(String posId) {
+ PosRef probe = new PosRef();
+ probe.posId = posId;
+ try {
+ List posList = posRefRepository.findAll(Example.of(probe));
+
+ if (posList.isEmpty()) {
+ log.warn("checkPosStatus NOK, unknown posId {}", posId);
+ return false;
+ }
+
+ boolean result = posList.get(0).active;
+
+ if (!result) {
+ log.warn("checkPosStatus NOK, inactive posId {}", posId);
+ }
+ return result;
+ } catch (NullPointerException e) {
+ log.warn("Invalid value for this POS: {}", posId);
+ throw e;
+ }
+}
+```
+
+You can also prevent this issue by simply fixing the SQL import file.
In the file ``easypay-service/src/main/resources/db/postgresql/data.sql``, Modify the implied line for ``POS-02`` from:
@@ -517,9 +510,13 @@ Restart the application activating the ``mdc`` profile and see how the logs look
./gradlew :easypay-service:bootRun -x test --args='--spring.profiles.active=default,mdc'
```
-> aside negative
+> aside positive
>
-> TODO Mettre comment vérifier que le bon profil a été démarré
+> You can verify the MDC profile is applied by checking the presence of this log message:
+> ```shell
+The following 2 profiles are active: "default", "mdc"
+```
+>
### Adding more content in our logs
@@ -553,10 +550,6 @@ We use then [Promtail to broadcast them to Loki](https://grafana.com/grafana/das
Check out the Logging configuration in the ``docker/alloy/config.alloy`` file:
-> aside negative
->
-> TODO mettre à jour
-
```json
////////////////////
// LOGS
@@ -651,7 +644,7 @@ Check out the logs again, view it now as a table.
You can also view traces for the other services (e.g., ``api-gateway``)
-Finally, you can search logs absed on the correlation ID
+Finally, you can search logs based on the correlation ID
> aside negative
>
@@ -672,7 +665,7 @@ Explore the output
Now get the prometheus metrics using this command:
```bash
-http :8080/actuator/metrics
+http :8080/actuator/prometheus
```
You can also have an overview of all the prometheus endpoints metrics on the Prometheus dashboad .
@@ -700,7 +693,6 @@ Explore the dashboard, especially the Garbage collector and CPU statistics.
Look around the JDBC dashboard then and see what happens on the database connection pool.
-
> aside negative
>
> TODO Détailler
@@ -725,10 +717,25 @@ Normally you will see the used JVM Heap reaching the maximum allowed.
## Traces
Duration: 0:20:00
-Stop the easypay service
+Stop the easypay service.
+
+Open the ``easypay.sh`` script file. You will then how is configured the JVM startup with the ``-javaagent`` parameter.
+
+```shell
+#!/usr/bin/env bash
+
+export OTEL_SERVICE_NAME=easypay-service
+export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
+export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
+export OTEL_RESOURCE_ATTRIBUTES="source=agent"
+
+export SERVER_PORT=8081
+export LOGS_DIRECTORY="$(pwd)/logs"
+
+java -Xms512m -Xmx512m -javaagent:$(pwd)/instrumentation/grafana-opentelemetry-java.jar -jar "$(pwd)/easypay-service/build/libs/easypay-service-0.0.1-SNAPSHOT.jar" "$@"
+```
-Open the ``easypay.sh`` script file. You will then see the ``-javaagent`` parameter.
-During this workshop, we will use a OpenTelemetry agent for broadcasting traces through Alloy to Tempo.
+During this workshop, we will use an OpenTelemetry agent for broadcasting traces through Alloy to Tempo.
Check the environment variables used:
diff --git a/easypay-service/build.gradle.kts b/easypay-service/build.gradle.kts
index 7ae4fa2..f72eaec 100644
--- a/easypay-service/build.gradle.kts
+++ b/easypay-service/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
java
- id("org.springframework.boot") version "3.2.5"
- id("io.spring.dependency-management") version "1.1.4"
+ id("org.springframework.boot") version "3.3.1"
+ id("io.spring.dependency-management") version "1.1.5"
}
group = "com.worldline.easypay"
@@ -15,7 +15,7 @@ repositories {
mavenCentral()
}
-extra["springCloudVersion"] = "2023.0.1"
+extra["springCloudVersion"] = "2023.0.2"
extra["springDocVersion"] = "2.5.0"
dependencies {
@@ -26,7 +26,6 @@ dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.cloud:spring-cloud-starter-loadbalancer")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
- // implementation("io.github.danielliu1123:httpexchange-spring-boot-starter:3.2.5")
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
implementation("org.springframework.cloud:spring-cloud-stream")
@@ -52,6 +51,9 @@ dependencies {
runtimeOnly("com.h2database:h2")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
+
+ // Testcontainers PostgreSQL
+ testImplementation("org.testcontainers:postgresql")
}
dependencyManagement {
@@ -62,4 +64,4 @@ dependencyManagement {
tasks.withType {
useJUnitPlatform()
-}
\ No newline at end of file
+}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/EasypayServiceApplication.java b/easypay-service/src/main/java/com/worldline/easypay/EasypayServiceApplication.java
index 74761cb..1944289 100644
--- a/easypay-service/src/main/java/com/worldline/easypay/EasypayServiceApplication.java
+++ b/easypay-service/src/main/java/com/worldline/easypay/EasypayServiceApplication.java
@@ -1,13 +1,12 @@
package com.worldline.easypay;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
-import com.worldline.easypay.payment.control.bank.BankAuthorClient;
-
-
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@@ -16,5 +15,4 @@ public class EasypayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EasypayServiceApplication.class, args);
}
-
}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/config/PrometheusRegistryConfiguration.java b/easypay-service/src/main/java/com/worldline/easypay/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..461dae4
--- /dev/null
+++ b/easypay-service/src/main/java/com/worldline/easypay/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/payment/boundary/PaymentResource.java b/easypay-service/src/main/java/com/worldline/easypay/payment/boundary/PaymentResource.java
index 713c58d..7197790 100644
--- a/easypay-service/src/main/java/com/worldline/easypay/payment/boundary/PaymentResource.java
+++ b/easypay-service/src/main/java/com/worldline/easypay/payment/boundary/PaymentResource.java
@@ -4,12 +4,18 @@
import java.util.List;
import java.util.UUID;
+import org.jboss.logging.MDC;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@@ -23,11 +29,14 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
+import org.springframework.http.HttpStatus;
@RestController
@RequestMapping("/payments")
public class PaymentResource {
+ private static final Logger LOG = LoggerFactory.getLogger(PaymentResource.class);
+
PaymentService paymentService;
public PaymentResource(PaymentService paymentService) {
@@ -67,7 +76,8 @@ public ResponseEntity findById(
@ApiResponse(responseCode = "201", description = "Payment processed", content = @Content(mediaType = "application/json"))
public ResponseEntity processPayment(
@Parameter(description = "The payment to be processed", required = true) @Valid @NotNull @RequestBody PaymentRequest paymentRequest) {
-
+ MDC.put("context", paymentRequest);
+ LOG.info("Processing new payment: {}", paymentRequest);
PaymentProcessingContext paymentContext = new PaymentProcessingContext(paymentRequest);
paymentService.accept(paymentContext);
@@ -76,7 +86,8 @@ public ResponseEntity processPayment(
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(response.paymentId()).toUri();
- return ResponseEntity.created(location).body(response);
+ var httpResponse = ResponseEntity.created(location).body(response);
+ MDC.clear();
+ return httpResponse;
}
-
}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/payment/control/CardValidator.java b/easypay-service/src/main/java/com/worldline/easypay/payment/control/CardValidator.java
index 3a25ce6..331d57b 100644
--- a/easypay-service/src/main/java/com/worldline/easypay/payment/control/CardValidator.java
+++ b/easypay-service/src/main/java/com/worldline/easypay/payment/control/CardValidator.java
@@ -34,8 +34,9 @@ public boolean checkExpiryDate(String expiryDate) {
YearMonth expiration = YearMonth.parse(expiryDate, DATE_TIME_FORMATTER);
YearMonth today = YearMonth.now();
boolean rc = expiration.equals(today) || expiration.isAfter(today);
- if (!rc)
+ if (!rc) {
log.warn("checkExpiryDate NOK: outdated: {}", expiryDate);
+ }
return rc;
} catch (DateTimeParseException e) {
log.warn("checkExpiryDate NOK: bad format: {}", expiryDate);
@@ -77,8 +78,6 @@ public boolean isBlackListed(String cardNumber) {
probe.blackListed = true;
long count = cardRepository.count(Example.of(probe));
- // long count = em.createNamedQuery("CardRef.isBlackListed",
- // Long.class).setParameter("cardNumber", cardNumber).getSingleResult();
if (count != 0) {
log.warn("cardNumber {} is black listed", cardNumber);
return true;
@@ -89,13 +88,14 @@ public boolean isBlackListed(String cardNumber) {
public boolean checkCardNumber(String cardNumber) {
- // Check format
- String card = cardNumber.replaceAll("[^0-9]+", ""); // remove all non-numerics
+ //* Check format
+ String card = cardNumber.replaceAll("[^0-9]+", ""); //* remove all non-numerics
if ((card == null) || (card.length() < 13) || (card.length() > 19)) {
+ log.warn("Invalid card format");
return false;
}
- // Check Luhn key
+ //* Check Luhn key
return checkLuhnKey(card);
}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/payment/control/PaymentService.java b/easypay-service/src/main/java/com/worldline/easypay/payment/control/PaymentService.java
index c3a2672..0115462 100644
--- a/easypay-service/src/main/java/com/worldline/easypay/payment/control/PaymentService.java
+++ b/easypay-service/src/main/java/com/worldline/easypay/payment/control/PaymentService.java
@@ -20,7 +20,7 @@
@Service
public class PaymentService {
- // add 1
+ //* Instantiate Logger
private static final Logger log = LoggerFactory.getLogger(PaymentService.class);
private CardValidator cardValidator;
@@ -49,6 +49,7 @@ private void process(PaymentProcessingContext context) {
}
if (!cardValidator.checkCardNumber(context.cardNumber)) {
+ log.warn("Card validation KO: {}", context.cardNumber);
context.responseCode = PaymentResponseCode.INVALID_CARD_NUMBER;
return;
}
@@ -67,9 +68,9 @@ private void process(PaymentProcessingContext context) {
if (context.amount > authorThreshold) {
if (!bankAuthorService.authorize(context)) {
- // Authorization refused: locally (AMOUNT_EXCEEDED) or remotely by the Bank
- // (AUTHORIZATION_DENIED)?
- // log.info("JJS => refused authorization, context=" + context);
+ //* Authorization refused: locally (AMOUNT_EXCEEDED) or remotely by the Bank
+ //* (AUTHORIZATION_DENIED)?
+ log.info("JJS => refused authorization, context=" + context);
context.responseCode = context.processingMode.equals(ProcessingMode.STANDARD)
? PaymentResponseCode.AUTHORIZATION_DENIED
: PaymentResponseCode.AMOUNT_EXCEEDED;
@@ -103,7 +104,6 @@ private void store(PaymentProcessingContext context) {
}
@Transactional(Transactional.TxType.REQUIRED)
- // @TrackedPayment
public void accept(PaymentProcessingContext paymentContext) {
process(paymentContext);
store(paymentContext);
diff --git a/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorConfig.java b/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorConfig.java
deleted file mode 100644
index acef6cd..0000000
--- a/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorConfig.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.worldline.easypay.payment.control.bank;
-
-import org.springframework.cloud.client.loadbalancer.LoadBalanced;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.client.RestClient;
-import org.springframework.web.client.support.RestClientAdapter;
-import org.springframework.web.service.invoker.HttpServiceProxyFactory;
-
-// @Configuration
-public class BankAuthorConfig {
-
- //@Bean
- //@LoadBalanced
- public RestClient.Builder restClient() {
- return RestClient.builder();
- }
-
-
- // @Bean
- BankAuthorClient produceBankAuthorClient(RestClient.Builder restClient) {
- RestClientAdapter adapter = RestClientAdapter.create(restClient.build());
- HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
- return factory.createClient(BankAuthorClient.class);
- }
-
-}
diff --git a/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorService.java b/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorService.java
index f10939b..5c80e94 100644
--- a/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorService.java
+++ b/easypay-service/src/main/java/com/worldline/easypay/payment/control/bank/BankAuthorService.java
@@ -4,7 +4,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -24,12 +23,10 @@ public class BankAuthorService {
@Value("${payment.max.amount.fallback:20000}")
Long maxAmountFallback;
-
- @Autowired
private BankAuthorClient client;
- public BankAuthorService(/*BankAuthorClient client*/) {
- //this.client = client;
+ public BankAuthorService(BankAuthorClient client) {
+ this.client = client;
}
private BankAuthorRequest initRequest(PaymentProcessingContext context) {
@@ -56,7 +53,7 @@ public boolean authorize(PaymentProcessingContext context) {
}
public boolean acceptByDelegation(PaymentProcessingContext context, Throwable throwable) {
- log.debug("Accept by delegation. Error was: {}", throwable.getMessage());
+ log.info("Accept by delegation. Error was: {}", throwable.getMessage());
context.bankCalled = false;
context.processingMode = ProcessingMode.FALLBACK;
return context.amount < maxAmountFallback;
diff --git a/easypay-service/src/main/resources/application-mdc.properties b/easypay-service/src/main/resources/application-mdc.properties
new file mode 100644
index 0000000..7aedc53
--- /dev/null
+++ b/easypay-service/src/main/resources/application-mdc.properties
@@ -0,0 +1 @@
+logging.pattern.console=%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr(%applicationName[%15.15t]){faint} %clr(${LOG_CORRELATION_PATTERN:-}){faint}%clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr(CONTEXT=){faint}%clr(%X{context:-null}) %m%n%wEx
\ No newline at end of file
diff --git a/easypay-service/src/main/resources/application.properties b/easypay-service/src/main/resources/application.properties
index eade731..4a577fe 100644
--- a/easypay-service/src/main/resources/application.properties
+++ b/easypay-service/src/main/resources/application.properties
@@ -1,6 +1,8 @@
spring.application.name=easypay-service
spring.application.instance=${spring.application.name}:${random.uuid}
+server.port=8081
+
spring.config.import=optional:configserver:${CONFIG_SERVER_URL:http://localhost:8888}
# AOT / Native Image does not support Spring Cloud Refresh Scope
@@ -18,4 +20,5 @@ resilience4j.retry.instances.BankAuthorService.enable-exponential-backoff=true
resilience4j.retry.instances.BankAuthorService.exponential-backoff-multiplier=2
resilience4j.retry.instances.BankAuthorService.retry-exceptions=feign.RetryableException
-spring.cloud.inetutils.preferred-networks=192.168.
\ No newline at end of file
+spring.cloud.inetutils.preferred-networks=192.168.
+spring.cloud.refresh.enabled=false
\ No newline at end of file
diff --git a/easypay-service/src/main/resources/logback-spring.xml b/easypay-service/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/easypay-service/src/main/resources/logback-spring.xml
+++ b/easypay-service/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/easypay-service/src/test/java/com/worldline/easypay/easypayservice/EasypayServiceApplicationTests.java b/easypay-service/src/test/java/com/worldline/easypay/easypayservice/EasypayServiceApplicationTests.java
index f1f4081..60c4d4e 100644
--- a/easypay-service/src/test/java/com/worldline/easypay/easypayservice/EasypayServiceApplicationTests.java
+++ b/easypay-service/src/test/java/com/worldline/easypay/easypayservice/EasypayServiceApplicationTests.java
@@ -1,11 +1,39 @@
package com.worldline.easypay.easypayservice;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.PostgreSQLContainer;
-@SpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class EasypayServiceApplicationTests {
+ @LocalServerPort
+ private Integer port;
+
+ static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
+
+ @BeforeAll
+ static void beforeAll() {
+ postgres.start();
+ }
+
+ @AfterAll
+ static void afterAll() {
+ postgres.stop();
+ }
+
+ @DynamicPropertySource
+ static void configureProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
+ registry.add("spring.datasource.username", postgres::getUsername);
+ registry.add("spring.datasource.password", postgres::getPassword);
+ }
+
@Test
void contextLoads() {
}
diff --git a/easypay-service/src/test/resources/application.properties b/easypay-service/src/test/resources/application.properties
new file mode 100644
index 0000000..7f23d6f
--- /dev/null
+++ b/easypay-service/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+spring.cloud.config.enabled=false
+eureka.client.enabled=false
diff --git a/easypay-service/src/test/resources/logback-test.xml b/easypay-service/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/easypay-service/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/easypay.sh b/easypay.sh
new file mode 100755
index 0000000..5a96015
--- /dev/null
+++ b/easypay.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+export OTEL_SERVICE_NAME=easypay-service
+export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
+export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
+export OTEL_RESOURCE_ATTRIBUTES="source=agent"
+
+export SERVER_PORT=8081
+export LOGS_DIRECTORY="$(pwd)/logs"
+
+java -Xms512m -Xmx512m -javaagent:$(pwd)/instrumentation/grafana-opentelemetry-java.jar -jar "$(pwd)/easypay-service/build/libs/easypay-service-0.0.1-SNAPSHOT.jar" "$@"
diff --git a/fraudetect-service/build.gradle.kts b/fraudetect-service/build.gradle.kts
index df8b327..194ad69 100644
--- a/fraudetect-service/build.gradle.kts
+++ b/fraudetect-service/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
java
- id("org.springframework.boot") version "3.3.0"
+ id("org.springframework.boot") version "3.3.1"
id("io.spring.dependency-management") version "1.1.5"
}
@@ -15,7 +15,7 @@ repositories {
mavenCentral()
}
-extra["springCloudVersion"] = "2023.0.1"
+extra["springCloudVersion"] = "2023.0.2"
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
@@ -42,10 +42,16 @@ dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
+
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.cloud:spring-cloud-stream-test-binder")
testImplementation("org.springframework.kafka:spring-kafka-test")
+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+
+ // Testcontainers PostgreSQL
+ testImplementation("org.testcontainers:postgresql")
+ testImplementation("org.testcontainers:kafka")
}
dependencyManagement {
diff --git a/fraudetect-service/src/main/docker/Dockerfile b/fraudetect-service/src/main/docker/Dockerfile
index 80517f0..a3b609f 100644
--- a/fraudetect-service/src/main/docker/Dockerfile
+++ b/fraudetect-service/src/main/docker/Dockerfile
@@ -1,4 +1,9 @@
FROM eclipse-temurin:21-jdk-alpine as build
+
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
WORKDIR /workspace/app
ENV SERVICE=fraudetect-service
@@ -14,6 +19,10 @@ RUN mkdir -p ${SERVICE}/build/dependency && (cd ${SERVICE}/build/dependency && j
FROM eclipse-temurin:21-jre-alpine
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
ENV SERVICE=fraudetect-service
ENV LOGS_DIRECTORY=/logs/
diff --git a/fraudetect-service/src/main/java/com/worldline/easypay/fraudetect/config/PrometheusRegistryConfiguration.java b/fraudetect-service/src/main/java/com/worldline/easypay/fraudetect/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..39aef18
--- /dev/null
+++ b/fraudetect-service/src/main/java/com/worldline/easypay/fraudetect/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.fraudetect.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/fraudetect-service/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java b/fraudetect-service/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
deleted file mode 100644
index d7ac5e2..0000000
--- a/fraudetect-service/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
-import ch.qos.logback.classic.spi.IThrowableProxy;
-
-/**
- * From: https://stackoverflow.com/a/47771943
- */
-public class CompressedStackTraceConverter extends ThrowableProxyConverter {
- @Override
- protected String throwableProxyToString(IThrowableProxy tp) {
- String original = super.throwableProxyToString(tp);
-
- // replace the new line characters with something,
- // use your own replacement value here
- return original.replaceAll("\n", " ~~ ");
- }
-}
diff --git a/fraudetect-service/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java b/fraudetect-service/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
deleted file mode 100644
index f182c9f..0000000
--- a/fraudetect-service/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.contrib.json.classic.JsonLayout;
-import java.util.Map;
-
-
-public class CustomJsonLayout extends JsonLayout {
-
- private static final String APPLICATION_NAME = "application";
- private static final String APPLICATION_INSTANCE = "instance";
-
- private String applicationName;
- private String applicationInstance;
-
- public CustomJsonLayout() {
- super();
- }
-
- @Override
- protected void addCustomDataToJsonMap(Map map, ILoggingEvent event) {
- add(APPLICATION_NAME, applicationName != null, applicationName, map);
- add(APPLICATION_INSTANCE, applicationInstance != null, applicationInstance, map);
- }
-
- public String getApplicationName(String applicationName) {
- return applicationName;
- }
-
- public void setApplicationName(String applicationName) {
- this.applicationName = applicationName;
- }
-
- public String getApplicationInstance(String applicationInstance) {
- return applicationInstance;
- }
-
- public void setApplicationInstance(String applicationInstance) {
- this.applicationInstance = applicationInstance;
- }
-}
\ No newline at end of file
diff --git a/fraudetect-service/src/main/resources/logback-spring.xml b/fraudetect-service/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/fraudetect-service/src/main/resources/logback-spring.xml
+++ b/fraudetect-service/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect/FraudetectServiceApplicationTests.java b/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect/FraudetectServiceApplicationTests.java
new file mode 100644
index 0000000..7889ce2
--- /dev/null
+++ b/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect/FraudetectServiceApplicationTests.java
@@ -0,0 +1,50 @@
+package com.worldline.easypay.fraudetect;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.KafkaContainer;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.utility.DockerImageName;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class FraudetectServiceApplicationTests {
+
+ @LocalServerPort
+ private Integer port;
+
+ static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
+
+ static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.6.1"));
+
+ @BeforeAll
+ static void beforeAll() {
+ postgres.start();
+ kafka.start();
+ }
+
+ @AfterAll
+ static void afterAll() {
+ postgres.stop();
+ kafka.stop();
+ }
+
+ @DynamicPropertySource
+ static void configureProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
+ registry.add("spring.datasource.username", postgres::getUsername);
+ registry.add("spring.datasource.password", postgres::getPassword);
+
+ registry.add("spring.kafka.bootstrap-servers", kafka::getBootstrapServers);
+ registry.add("spring.cloud.stream.kafka.binder.defaultBrokerPort", () -> kafka.getMappedPort(KafkaContainer.KAFKA_PORT));
+ }
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect_service/FraudetectServiceApplicationTests.java b/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect_service/FraudetectServiceApplicationTests.java
deleted file mode 100644
index 96a5336..0000000
--- a/fraudetect-service/src/test/java/com/worldline/easypay/fraudetect_service/FraudetectServiceApplicationTests.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.worldline.easypay.fraudetect_service;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class FraudetectServiceApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
diff --git a/fraudetect-service/src/test/resources/application.properties b/fraudetect-service/src/test/resources/application.properties
new file mode 100644
index 0000000..9dcf0d9
--- /dev/null
+++ b/fraudetect-service/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+eureka.client.enabled=false
+spring.cloud.config.enabled=false
diff --git a/fraudetect-service/src/test/resources/logback-test.xml b/fraudetect-service/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/fraudetect-service/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b82aa23..e2b3e26 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
-networkTimeout=10000
+networkTimeout=60000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/k6-script.js b/k6-script.js
deleted file mode 100644
index 6906661..0000000
--- a/k6-script.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import http from 'k6/http';
-import { sleep } from 'k6';
-
-export default function() {
-
-}
\ No newline at end of file
diff --git a/k6/01-payment-only.js b/k6/01-payment-only.js
new file mode 100644
index 0000000..166076e
--- /dev/null
+++ b/k6/01-payment-only.js
@@ -0,0 +1,42 @@
+import http from 'k6/http';
+import { sleep } from 'k6';
+import { check } from 'k6';
+import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
+
+const cardNumbers = [
+ '5204460010000007',
+ '5204460010000015',
+ '5204460010000023',
+ '5204460010000031',
+ '5204460010000049',
+ '5204460010000056',
+ '5204460010000057'
+]
+const posIds = ["POS-01", "POS-02"]
+const url = 'http://localhost:8080/api/easypay/payments'
+const params = {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': '*/*',
+ },
+ };
+
+export default function() {
+ const randomCardNumber = randomItem(cardNumbers);
+ const randomPosId = randomItem(posIds);
+
+ const payload = JSON.stringify({
+ 'posId': randomPosId,
+ 'cardNumber': randomCardNumber,
+ 'expiryDate': '09/25',
+ 'amount': "40000"
+ })
+
+ const res = http.post(url, payload, params);
+
+ check(res, {
+
+ 'is status 201': (r) => r.status === 201,
+
+ });
+}
\ No newline at end of file
diff --git a/k6/02-payment-smartbank.js b/k6/02-payment-smartbank.js
new file mode 100644
index 0000000..c7fa0fd
--- /dev/null
+++ b/k6/02-payment-smartbank.js
@@ -0,0 +1,53 @@
+import http from 'k6/http';
+import { sleep } from 'k6';
+import { check } from 'k6';
+import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
+
+const cardNumbers = [
+ '5204460010000007',
+ '5204460010000015',
+ '5204460010000023',
+ '5204460010000031',
+ '5204460010000049',
+ '5204460010000056',
+ //'5204460010000057'
+]
+const posIds = ["POS-01"]
+const url = 'http://localhost:8080/api/easypay/payments'
+const params = {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': '*/*',
+ },
+ };
+
+export default function() {
+ const randomCardNumber = randomItem(cardNumbers);
+ const randomPosId = randomItem(posIds);
+
+ const payload = JSON.stringify({
+ 'posId': randomPosId,
+ 'cardNumber': randomCardNumber,
+ 'expiryDate': '09/25',
+ 'amount': "40000"
+ })
+
+ const res = http.post(url, payload, params);
+
+ check(res, {
+
+ 'is status 201': (r) => r.status === 201,
+
+ });
+
+ if (res.json('bankCalled') === false) {
+ console.log('Warning: Bank was not called!!!!! Unavailable?')
+ } else {
+ const authorId = res.json('authorId');
+ const bankRes = http.get(`http://localhost:8080/api/smartbank/authors/${authorId}`);
+
+ check(bankRes, {
+ 'is status 200': (r) => r.status === 200,
+ })
+ }
+}
\ No newline at end of file
diff --git a/merchant-backoffice/build.gradle.kts b/merchant-backoffice/build.gradle.kts
index 317a12c..71d326c 100644
--- a/merchant-backoffice/build.gradle.kts
+++ b/merchant-backoffice/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
java
- id("org.springframework.boot") version "3.3.0"
+ id("org.springframework.boot") version "3.3.1"
id("io.spring.dependency-management") version "1.1.5"
}
@@ -50,6 +50,9 @@ dependencies {
testImplementation("org.springframework.graphql:spring-graphql-test")
testImplementation("org.springframework.kafka:spring-kafka-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+
+ // Testcontainers PostgreSQL
+ testImplementation("org.testcontainers:postgresql")
}
dependencyManagement {
diff --git a/merchant-backoffice/src/main/docker/Dockerfile b/merchant-backoffice/src/main/docker/Dockerfile
index 4e94314..9fd942a 100644
--- a/merchant-backoffice/src/main/docker/Dockerfile
+++ b/merchant-backoffice/src/main/docker/Dockerfile
@@ -1,4 +1,9 @@
FROM eclipse-temurin:21-jdk-alpine as build
+
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
WORKDIR /workspace/app
ENV SERVICE=merchant-backoffice
@@ -14,6 +19,10 @@ RUN mkdir -p ${SERVICE}/build/dependency && (cd ${SERVICE}/build/dependency && j
FROM eclipse-temurin:21-jre-alpine
+# INSTALL CA Certificates (useful for companies with SSL inspection)
+ADD --chmod=644 docker/ca-trust/* /certificates/
+RUN export USE_SYSTEM_CA_CERTS=1 && /__cacert_entrypoint.sh
+
ENV SERVICE=merchant-backoffice
ENV LOGS_DIRECTORY=/logs/
diff --git a/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java b/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
deleted file mode 100644
index d7ac5e2..0000000
--- a/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CompressedStackTraceConverter.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
-import ch.qos.logback.classic.spi.IThrowableProxy;
-
-/**
- * From: https://stackoverflow.com/a/47771943
- */
-public class CompressedStackTraceConverter extends ThrowableProxyConverter {
- @Override
- protected String throwableProxyToString(IThrowableProxy tp) {
- String original = super.throwableProxyToString(tp);
-
- // replace the new line characters with something,
- // use your own replacement value here
- return original.replaceAll("\n", " ~~ ");
- }
-}
diff --git a/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java b/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
deleted file mode 100644
index f182c9f..0000000
--- a/merchant-backoffice/src/main/java/com/worldline/easypay/logging/CustomJsonLayout.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.worldline.easypay.logging;
-
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.contrib.json.classic.JsonLayout;
-import java.util.Map;
-
-
-public class CustomJsonLayout extends JsonLayout {
-
- private static final String APPLICATION_NAME = "application";
- private static final String APPLICATION_INSTANCE = "instance";
-
- private String applicationName;
- private String applicationInstance;
-
- public CustomJsonLayout() {
- super();
- }
-
- @Override
- protected void addCustomDataToJsonMap(Map map, ILoggingEvent event) {
- add(APPLICATION_NAME, applicationName != null, applicationName, map);
- add(APPLICATION_INSTANCE, applicationInstance != null, applicationInstance, map);
- }
-
- public String getApplicationName(String applicationName) {
- return applicationName;
- }
-
- public void setApplicationName(String applicationName) {
- this.applicationName = applicationName;
- }
-
- public String getApplicationInstance(String applicationInstance) {
- return applicationInstance;
- }
-
- public void setApplicationInstance(String applicationInstance) {
- this.applicationInstance = applicationInstance;
- }
-}
\ No newline at end of file
diff --git a/merchant-backoffice/src/main/java/com/worldline/easypay/merchantbo/config/PrometheusRegistryConfiguration.java b/merchant-backoffice/src/main/java/com/worldline/easypay/merchantbo/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..d0e7895
--- /dev/null
+++ b/merchant-backoffice/src/main/java/com/worldline/easypay/merchantbo/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.merchantbo.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/merchant-backoffice/src/main/resources/logback-spring.xml b/merchant-backoffice/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/merchant-backoffice/src/main/resources/logback-spring.xml
+++ b/merchant-backoffice/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/merchant-backoffice/src/test/java/com/worldline/easypay/merchantbo/MerchantBackofficeApplicationTests.java b/merchant-backoffice/src/test/java/com/worldline/easypay/merchantbo/MerchantBackofficeApplicationTests.java
index 3f33bcd..d9fd060 100644
--- a/merchant-backoffice/src/test/java/com/worldline/easypay/merchantbo/MerchantBackofficeApplicationTests.java
+++ b/merchant-backoffice/src/test/java/com/worldline/easypay/merchantbo/MerchantBackofficeApplicationTests.java
@@ -1,11 +1,39 @@
package com.worldline.easypay.merchantbo;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.PostgreSQLContainer;
-@SpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MerchantBackofficeApplicationTests {
+ @LocalServerPort
+ private Integer port;
+
+ static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
+
+ @BeforeAll
+ static void beforeAll() {
+ postgres.start();
+ }
+
+ @AfterAll
+ static void afterAll() {
+ postgres.stop();
+ }
+
+ @DynamicPropertySource
+ static void configureProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
+ registry.add("spring.datasource.username", postgres::getUsername);
+ registry.add("spring.datasource.password", postgres::getPassword);
+ }
+
@Test
void contextLoads() {
}
diff --git a/merchant-backoffice/src/test/resources/application.properties b/merchant-backoffice/src/test/resources/application.properties
new file mode 100644
index 0000000..1352832
--- /dev/null
+++ b/merchant-backoffice/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+spring.cloud.config.enabled=false
+eureka.client.enabled=false
\ No newline at end of file
diff --git a/merchant-backoffice/src/test/resources/logback-test.xml b/merchant-backoffice/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/merchant-backoffice/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/smartbank-gateway/build.gradle.kts b/smartbank-gateway/build.gradle.kts
index cbecde4..bab2a64 100644
--- a/smartbank-gateway/build.gradle.kts
+++ b/smartbank-gateway/build.gradle.kts
@@ -1,8 +1,7 @@
plugins {
java
- id("org.springframework.boot") version "3.2.5"
- id("io.spring.dependency-management") version "1.1.4"
-// id("org.graalvm.buildtools.native") version "0.9.28"
+ id("org.springframework.boot") version "3.3.1"
+ id("io.spring.dependency-management") version "1.1.5"
}
group = "com.worldline.easypay"
@@ -16,21 +15,41 @@ repositories {
mavenCentral()
}
-extra["springCloudVersion"] = "2023.0.1"
+extra["springCloudVersion"] = "2023.0.2"
extra["springDocVersion"] = "2.5.0"
dependencies {
- implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.cloud:spring-cloud-starter-config")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
+
+ // Expose metrics with Micrometer using a Prometheus registry
+ implementation("org.springframework.boot:spring-boot-starter-actuator")
+ implementation("io.micrometer:micrometer-registry-prometheus")
+
+ // Add opentelemetry exemplars support
+ implementation(platform("io.opentelemetry:opentelemetry-bom:1.38.0"))
+ implementation("io.opentelemetry:opentelemetry-api")
+ implementation("io.prometheus:prometheus-metrics-tracer-otel-agent:1.3.1")
+
+ // Logging
+ implementation("ch.qos.logback.contrib:logback-json-classic:0.1.5")
+ implementation("ch.qos.logback.contrib:logback-jackson:0.1.5")
+
+ // Add caching support
+ implementation("org.springframework.boot:spring-boot-starter-cache")
+ implementation("com.hazelcast:hazelcast-all:4.2.8")
+
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:${property("springDocVersion")}")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("com.h2database:h2")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
+
+ // Testcontainers PostgreSQL
+ testImplementation("org.testcontainers:postgresql")
}
dependencyManagement {
diff --git a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/boundary/BankAuthorResource.java b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/boundary/BankAuthorResource.java
index 9c12065..aebfbe6 100644
--- a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/boundary/BankAuthorResource.java
+++ b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/boundary/BankAuthorResource.java
@@ -17,6 +17,7 @@
import com.worldline.easypay.smartbank.bankauthor.control.AuthorizationService;
import com.worldline.easypay.smartbank.bankauthor.control.BankAuthorBoundaryControl;
+import com.worldline.easypay.smartbank.cache.CacheRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -24,17 +25,19 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
-
@RestController
@RequestMapping("/authors")
public class BankAuthorResource {
BankAuthorBoundaryControl bankAuthors;
AuthorizationService authorizationService;
+ CacheRepository cacheRepository;
- public BankAuthorResource(BankAuthorBoundaryControl boundaryControl, AuthorizationService validationService) {
+ public BankAuthorResource(BankAuthorBoundaryControl boundaryControl, AuthorizationService validationService,
+ CacheRepository cacheRepository) {
this.bankAuthors = boundaryControl;
this.authorizationService = validationService;
+ this.cacheRepository = cacheRepository;
}
@GetMapping("/count")
@@ -43,7 +46,6 @@ public ResponseEntity count() {
return ResponseEntity.ok().body(new BankAuthorCountResponse(this.bankAuthors.count()));
}
-
@GetMapping
@Operation(summary = "Get all payment authorizations", description = "Get all payment authorizations")
@ApiResponse(responseCode = "200", description = "List of payment authorizations found")
@@ -51,18 +53,23 @@ public ResponseEntity> findAll() {
return ResponseEntity.ok().body(this.bankAuthors.findAll());
}
-
@GetMapping(value = "/{id}")
@Operation(summary = "Get a payment authorization", description = "Get a payment authorization by its ID")
@ApiResponse(responseCode = "200", description = "Payment authorization found")
public ResponseEntity findById(
@Parameter(description = "The ID of the payment authorization to retrieve") @PathVariable("id") String id) {
try {
+ var author = (BankAuthorResponse) cacheRepository.get(id);
+ if (author != null) {
+ return ResponseEntity.ok().body(author);
+ }
+
var authorizationId = UUID.fromString(id);
Optional response = this.bankAuthors.findById(authorizationId);
if (response.isEmpty()) {
return ResponseEntity.notFound().build();
}
+ cacheRepository.put(id, response.get());
return ResponseEntity.ok().body(response.get());
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build();
@@ -74,9 +81,7 @@ public ResponseEntity findById(
@ApiResponse(responseCode = "201", description = "Payment authorization request processed successfully")
@Transactional
ResponseEntity authorize(@Valid @NotNull @RequestBody BankAuthorRequest request) {
- var authorized = this.authorizationService.authorize(request);
- var response = new BankAuthorResponse(UUID.randomUUID(), request.merchantId(), request.cardNumber(),
- request.expiryDate(), request.amount(), authorized);
+ var response = this.authorizationService.authorize(request);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(response.authorId()).toUri();
return ResponseEntity.created(location).body(response);
diff --git a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/control/AuthorizationService.java b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/control/AuthorizationService.java
index 2d3ba6b..ac612a3 100644
--- a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/control/AuthorizationService.java
+++ b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/bankauthor/control/AuthorizationService.java
@@ -6,6 +6,7 @@
import org.springframework.stereotype.Service;
import com.worldline.easypay.smartbank.bankauthor.boundary.BankAuthorRequest;
+import com.worldline.easypay.smartbank.bankauthor.boundary.BankAuthorResponse;
import com.worldline.easypay.smartbank.bankauthor.entity.BankAuthor;
import com.worldline.easypay.smartbank.bankauthor.entity.BankAuthorRepository;
@@ -24,7 +25,7 @@ public AuthorizationService(BankAuthorRepository repository, @Value("${smartbank
}
@Transactional(Transactional.TxType.MANDATORY)
- public boolean authorize(BankAuthorRequest bankAuthorRequest) {
+ public BankAuthorResponse authorize(BankAuthorRequest bankAuthorRequest) {
var authorized = bankAuthorRequest.amount() <= maxAmount;
// Record the bank author
@@ -38,6 +39,17 @@ public boolean authorize(BankAuthorRequest bankAuthorRequest) {
this.repository.save(author);
- return authorized;
+ return toResponse(author);
+ }
+
+ public BankAuthorResponse toResponse(BankAuthor bankAuthor) {
+ return new BankAuthorResponse(
+ bankAuthor.id,
+ bankAuthor.merchantId,
+ bankAuthor.cardNumber,
+ bankAuthor.expiryDate,
+ bankAuthor.amount,
+ bankAuthor.authorized
+ );
}
}
diff --git a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRecord.java b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRecord.java
new file mode 100644
index 0000000..2a9c885
--- /dev/null
+++ b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRecord.java
@@ -0,0 +1,9 @@
+package com.worldline.easypay.smartbank.cache;
+
+public record CacheRecord(
+ Object entry,
+ byte[] ioBuffer) {
+ public CacheRecord(Object entry) {
+ this(entry, new byte[1048576]);
+ }
+}
diff --git a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRepository.java b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRepository.java
new file mode 100644
index 0000000..a47848f
--- /dev/null
+++ b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/cache/CacheRepository.java
@@ -0,0 +1,30 @@
+package com.worldline.easypay.smartbank.cache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CacheRepository {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CacheRepository.class);
+
+ private Map cache = new HashMap<>();
+
+ public void put(String key, Object value) {
+ cache.put(key, new CacheRecord(value));
+ LOGGER.info("New heap size is now: {}/{}|{}", Runtime.getRuntime().totalMemory(), Runtime.getRuntime().maxMemory(), Runtime.getRuntime().freeMemory());
+ }
+
+ public Object get(String key) {
+ var record = cache.get(key);
+ if (record == null) {
+ return null;
+ }
+ return record.entry();
+ }
+
+}
diff --git a/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/config/PrometheusRegistryConfiguration.java b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/config/PrometheusRegistryConfiguration.java
new file mode 100644
index 0000000..d4e7f7b
--- /dev/null
+++ b/smartbank-gateway/src/main/java/com/worldline/easypay/smartbank/config/PrometheusRegistryConfiguration.java
@@ -0,0 +1,17 @@
+package com.worldline.easypay.smartbank.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.prometheus.metrics.tracer.otel_agent.OpenTelemetryAgentSpanContext;
+
+
+@Configuration
+public class PrometheusRegistryConfiguration {
+
+ @Bean
+ @ConditionalOnClass(name="io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span")
+ public OpenTelemetryAgentSpanContext exemplarConfigSupplier() {
+ return new OpenTelemetryAgentSpanContext();
+ }
+}
diff --git a/smartbank-gateway/src/main/resources/logback-spring.xml b/smartbank-gateway/src/main/resources/logback-spring.xml
index 53b23f9..b3fc0f6 100644
--- a/smartbank-gateway/src/main/resources/logback-spring.xml
+++ b/smartbank-gateway/src/main/resources/logback-spring.xml
@@ -8,39 +8,21 @@
-
-
-
-
-
- ${FILE_LOG_THRESHOLD}
-
-
- ${LOG_FILE}.json
-
-
- ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
- ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
- ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
- ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
- ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
-
-
-
-
-
-
-
+
+
+ ${FILE_LOG_THRESHOLD}
+
+
+ ${LOG_FILE}.json
+
+
+ ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}
+ ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}
+ ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}
+ ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}
+ ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}
+
+
diff --git a/smartbank-gateway/src/test/java/com/worldline/easypay/smartbank/SmartbankGatewayApplicationTests.java b/smartbank-gateway/src/test/java/com/worldline/easypay/smartbank/SmartbankGatewayApplicationTests.java
index e2f4637..3c1063a 100644
--- a/smartbank-gateway/src/test/java/com/worldline/easypay/smartbank/SmartbankGatewayApplicationTests.java
+++ b/smartbank-gateway/src/test/java/com/worldline/easypay/smartbank/SmartbankGatewayApplicationTests.java
@@ -1,11 +1,39 @@
package com.worldline.easypay.smartbank;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.PostgreSQLContainer;
-@SpringBootTest
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SmartbankGatewayApplicationTests {
+ @LocalServerPort
+ private Integer port;
+
+ static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
+
+ @BeforeAll
+ static void beforeAll() {
+ postgres.start();
+ }
+
+ @AfterAll
+ static void afterAll() {
+ postgres.stop();
+ }
+
+ @DynamicPropertySource
+ static void configureProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", postgres::getJdbcUrl);
+ registry.add("spring.datasource.username", postgres::getUsername);
+ registry.add("spring.datasource.password", postgres::getPassword);
+ }
+
@Test
void contextLoads() {
}
diff --git a/smartbank-gateway/src/test/resources/application.yml b/smartbank-gateway/src/test/resources/application.yml
new file mode 100644
index 0000000..5fde57f
--- /dev/null
+++ b/smartbank-gateway/src/test/resources/application.yml
@@ -0,0 +1,3 @@
+eureka:
+ client:
+ enabled: false
\ No newline at end of file
diff --git a/smartbank-gateway/src/test/resources/logback-test.xml b/smartbank-gateway/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..9b4499d
--- /dev/null
+++ b/smartbank-gateway/src/test/resources/logback-test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/smartbank.sh b/smartbank.sh
new file mode 100755
index 0000000..de547ad
--- /dev/null
+++ b/smartbank.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+export OTEL_SERVICE_NAME=smartbank-gateway
+export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
+export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
+export OTEL_RESOURCE_ATTRIBUTES="source=agent"
+export LOGS_DIRECTORY="$(pwd)/logs"
+
+java -Xms512m -Xmx512m -javaagent:$(pwd)/instrumentation/grafana-opentelemetry-java.jar -jar "$(pwd)/smartbank-gateway/build/libs/smartbank-gateway-0.0.1-SNAPSHOT.jar" "$@"