How cromeroprofile/spring-boot-monitoring works
1. This repo is a small Spring Boot 3 application written in Kotlin, focused on observability rather than business logic. The only visible application source file is KotlinMvcApplication.kt, which suggests a thin MVC entrypoint backed mostly by framework auto-configuration.
2. The application runtime is configured through two main files:
- src/main/resources/application.properties for Spring/Micrometer/Actuator behavior
- src/main/resources/logback-spring.xml for log shipping and log correlation
These two files are central to how the app emits telemetry.
3. The application’s request path is the standard Spring MVC layer: incoming HTTP traffic hits the Spring Boot app, which produces three observability signals from the same request context:
- metrics via Actuator/Micrometer
- distributed traces via Micrometer Tracing + Brave
- logs via Logback with trace context injected into the log pattern
4. Metrics flow from the app to Prometheus. Spring Boot exposes an /actuator/prometheus endpoint, and Prometheus scrapes it according to docker/prometheus/prometheus.yml. The README indicates histogram/percentile data is enabled so Prometheus samples can include trace_id/span_id exemplars.
5. Traces flow from the app to Grafana Tempo. The repo uses Zipkin-compatible tracing export (zipkin-reporter-brave in the README) and Tempo is configured to receive Zipkin-format spans. This makes Tempo the trace store for request-level latency and span inspection.
6. Logs flow from the app to Grafana Loki. logback-spring.xml configures a Loki appender, and the log pattern includes labels such as application name, host, log level, class, and importantly traceID. That trace label is what enables log-to-trace correlation.
7. Grafana is the read side of the system. It does not collect data itself; it queries the three backends:
- Prometheus for metrics
- Tempo for traces
- Loki for logs
The provided dashboard is centered on “Logs, Traces, Metrics” as a single observability view.
8. Correlation is the key architectural idea in this repo. The same trace context is propagated across metrics, logs, and traces, so a user can move from a metric exemplar to a trace, then jump from that trace into related logs. The README explicitly frames trace_id as the join key across all layers.
9. docker-compose.yml is the infrastructure boundary for the whole stack. It starts the observability services locally, so the application and the monitoring stack can be run as a self-contained demo environment without external dependencies.
10. The configuration files under docker/ are operationally important:
- Grafana provisioning files prewire datasources and dashboards
- Prometheus config defines scrape behavior
- Tempo config defines the tracing receiver/storage behavior
- Grafana provisioning auto-loads the dashboard and datasource setup
This means the repo is designed for repeatable local startup, not manual UI setup.
11. The project uses Maven (pom.xml) as the build and dependency manager. The README highlights the key dependencies that shape architecture: Spring Boot Actuator, Micrometer Prometheus registry, Micrometer Tracing with Brave, Zipkin reporter, and Loki4j Logback appender.
12. In diagram terms, the main boundaries are:
- client/request traffic into Spring Boot MVC
- telemetry egress from the app to Prometheus, Tempo, and Loki
- Grafana as the visualization/query layer over those stores
- Docker Compose as the environment orchestrator that ties everything together
Main entry points: docker-compose.yml Compose · KotlinMvcApplication.kt App entry · application.properties App props · datasource.yml Grafana datasources
Components 19
Application
Spring Boot request path and telemetry emission
- App entry · Thin Kotlin Spring Boot MVC entrypoint
src/main/kotlin/com/example/kotlinmvc/KotlinMvcApplication.kt - Spring MVC · Incoming HTTP request handling and controller runtime
- Actuator · Exposes application and Prometheus metrics
- Tracing · Propagates trace context and exports spans
- Logging · Logback pipeline with trace-aware log enrichment
Runtime Config
Application and observability configuration files
- App props · Spring and Micrometer runtime settings
src/main/resources/application.properties - Logback config · Loki appender and traceId-aware log pattern
src/main/resources/logback-spring.xml
Observability Stack
Local monitoring services and their wiring
- Compose · Starts the app and observability stack locally
docker-compose.yml - Prometheus cfg · Defines scrape target and metrics collection behavior
docker/prometheus/prometheus.yml - Tempo cfg · Configures Zipkin-format trace ingestion and storage
docker/tempo/tempo-local.yaml - Grafana datasources · Auto-wires Prometheus, Tempo, and Loki connections
docker/grafana/provisioning/datasources/datasource.yml - Grafana dashboard · Preloads the Logs, Traces, Metrics dashboard
docker/grafana/provisioning/dashboards/logs_traces_metrics.json - Dashboards cfg · Enables dashboard auto-loading
docker/grafana/provisioning/dashboards/dashboard.yml - Prometheus · Scrapes and stores application metrics and exemplars
- Tempo · Stores and serves distributed traces
- Loki · Stores application logs for correlation and search
- Grafana · Queries metrics, traces, and logs in one view
Other components
- Repo · Local demo stack for correlated logs, traces, and metrics
- Maven · Project build and dependency management
pom.xml
Connections 27
- Repo → Maven: built with · Maven manages build and dependencies
- Repo → Compose: runs in · Docker Compose defines the local demo environment
- Maven → App entry: packages · Build produces the Spring Boot application
- Compose → Prometheus: starts · Compose launches the metrics backend
- Compose → Tempo: starts · Compose launches the tracing backend
- Compose → Loki: starts · Compose launches the log backend
- Compose → Grafana: starts · Compose launches the visualization layer
- Compose → Prometheus cfg: mounts · Prometheus uses repo-provided scrape config
- Compose → Tempo cfg: mounts · Tempo uses repo-provided trace config
- Compose → Grafana datasources: mounts · Grafana loads datasources automatically
- Compose → Dashboards cfg: mounts · Grafana dashboard provisioning is enabled
- Compose → Grafana dashboard: loads · Grafana imports the bundled observability dashboard
- App entry → Spring MVC: handles requests · Spring MVC receives incoming HTTP traffic
- App entry → Actuator: exposes metrics · Actuator publishes Prometheus-friendly metrics
- App entry → Tracing: creates spans · Micrometer Tracing captures request spans
- App entry → Logging: emits logs · Logback writes trace-enriched application logs
- App props → Actuator: configures · Application properties tune actuator and metrics behavior
- App props → Tracing: configures · Application properties influence tracing export and sampling
- Logback config → Logging: configures · Logback config sets Loki appender and log pattern
- Spring MVC → Prometheus: scraped by · Prometheus collects metrics from the application endpoint
- Tracing → Tempo: exports to · Spans are sent in Zipkin-compatible format
- Logging → Loki: ships to · Logs are forwarded to Loki
- Prometheus → Grafana: queried by · Grafana reads metrics for dashboards
- Tempo → Grafana: queried by · Grafana reads traces for investigation
- Loki → Grafana: queried by · Grafana reads logs for correlation
- Grafana datasources → Grafana: provisions · Datasource provisioning connects Grafana to backends
- Grafana dashboard → Grafana: provisions · Dashboard provisioning loads the main observability view