Companion module for the rewritten ankurm.com Prometheus/Grafana monitoring post. Verified against a real running grafana/otel-lgtm container (not mocked): 8 real requests produce a real orders_placed_total metric queried back from the bundled Prometheus-compatible API with zero management.otlp.* properties, auto-wired entirely by Boot's Docker Compose service-connection detection. Two real findings surfaced along the way and documented rather than smoothed over: @Observed silently produces no span without an explicit ObservedAspect bean (AspectJ weaving alone is not sufficient, despite Micrometer Tracing being active), and OTEL_EXPORTER_OTLP_ENDPOINT already worked on Boot 4.0 via Micrometer's own OtlpConfig fallback -- what's actually new in 4.1 is the rest of the standard OTEL_* surface (verified with OTEL_METRIC_EXPORT_INTERVAL against identical source compiled on both Boot 4.0.8 and 4.1.1). Also fixes the root README's module table, which was missing a row for resilience4j-circuit-breaker (added in a previous commit but never indexed here).
90 lines
4.7 KiB
Markdown
90 lines
4.7 KiB
Markdown
# 1. Migrating to spring-boot-starter-opentelemetry
|
|
|
|
[README](../README.md) | Next: [2. The Observation API and @Observed](02-observation-api.md)
|
|
|
|
## What the old post 4700 used, and what replaces it
|
|
|
|
The original version of this article's post built a Prometheus + Grafana stack by hand: add
|
|
`micrometer-registry-prometheus`, expose `/actuator/prometheus`, run a Prometheus container with
|
|
a hand-written `prometheus.yml` scrape config pointed at `host.docker.internal:8080`, run a
|
|
Grafana container, wire up a data source, import a community dashboard by ID. That is still a
|
|
completely valid way to run Prometheus and Grafana, and nothing about it stopped working on
|
|
Spring Boot 4.1.
|
|
|
|
What's new is a fourth option, built by the Spring team and shipped as its own starter:
|
|
|
|
```xml
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-opentelemetry</artifactId>
|
|
</dependency>
|
|
```
|
|
|
|
One dependency replaces `micrometer-registry-prometheus` (or any other vendor-specific registry)
|
|
plus a tracing bridge. It pulls in `micrometer-registry-otlp` and
|
|
`micrometer-tracing-bridge-otel`, and switches the whole export model from **pull** (something
|
|
scrapes `/actuator/prometheus` on a timer) to **push** (the app itself POSTs metrics and traces,
|
|
in one vendor-neutral wire format, OTLP, to wherever you point it). This repo's module,
|
|
[`observability/`](../), uses this starter exclusively -- the deep, beginner-to-advanced
|
|
treatment of Micrometer versus OpenTelemetry, the Observation API, cardinality, and context
|
|
propagation already exists on this blog:
|
|
[Micrometer to OpenTelemetry: The Spring Boot 4 Observability Guide](https://ankurm.com/micrometer-opentelemetry-spring-boot-4-observability-guide/).
|
|
This module exists to verify one specific, narrower claim that guide states in passing but does
|
|
not itself demonstrate end to end: that Boot 4.1 will auto-wire the OTLP export path against a
|
|
real local collector with zero `management.otlp.*` properties, using nothing but Docker Compose.
|
|
|
|
## Docker Compose does the wiring, verified
|
|
|
|
[`compose.yaml`](../compose.yaml) names one image:
|
|
|
|
```yaml
|
|
services:
|
|
lgtm:
|
|
image: grafana/otel-lgtm:latest
|
|
ports:
|
|
- "3000:3000" # Grafana UI
|
|
- "4317:4317" # OTLP gRPC ingest
|
|
- "4318:4318" # OTLP HTTP ingest
|
|
- "9090:9090" # Prometheus-compatible query API
|
|
- "3200:3200" # Tempo query API (traces)
|
|
```
|
|
|
|
[`grafana/otel-lgtm`](https://github.com/grafana/docker-otel-lgtm) is a single image bundling
|
|
Loki, Grafana, Tempo and (Mimir-backed) Prometheus, plus an OTLP collector endpoint -- the exact
|
|
image the Spring team's own OpenTelemetry starter documentation uses as its local-development
|
|
example. [`application.yml`](../src/main/resources/application.yml) has no `management.otlp.*`
|
|
properties in it at all. Running `./scripts/run.sh` (which is `mvn spring-boot:run`) produces:
|
|
|
|
```console
|
|
DockerComposeLifecycleManager : Using Docker Compose file .../compose.yaml
|
|
DockerCli : Container obs-module-lgtm-1 Starting
|
|
DockerCli : Container obs-module-lgtm-1 Started
|
|
DockerCli : Container obs-module-lgtm-1 Healthy
|
|
PushMeterRegistry : Publishing metrics for OtlpMeterRegistry every 1m to http://127.0.0.1:4318/v1/metrics with resource attributes {service.name=order-service}
|
|
```
|
|
|
|
([00-docker-compose-auto-wiring.txt](output/00-docker-compose-auto-wiring.txt)) The important
|
|
detail is `127.0.0.1`, not `localhost`. Micrometer's own `OtlpConfig` defaults already point at
|
|
`localhost:4318` with nothing configured at all, so an app that happens to reuse the default OTLP
|
|
port could look auto-wired when it is actually just coincidental. `127.0.0.1` is what Boot's
|
|
Docker Compose service-connection support specifically resolves the container to; if you see
|
|
`localhost` instead, the auto-wiring did not actually happen and you are looking at the bare
|
|
Micrometer default.
|
|
|
|
## Real traffic, real metrics, real backend
|
|
|
|
8 real HTTP requests to a real running server, queried back out of the real Prometheus-compatible
|
|
API bundled inside the container -- not the app's own `/actuator/prometheus`, and no scraping
|
|
involved at all, since this is push, not pull:
|
|
|
|
```console
|
|
$ curl -s "http://localhost:9090/api/v1/query?query=orders_placed_total"
|
|
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"orders_placed_total", ...},"value":[..., "8"]}]}}
|
|
```
|
|
|
|
([01-metrics-and-traces-in-lgtm.txt](output/01-metrics-and-traces-in-lgtm.txt), source:
|
|
[`OrderController.java`](../src/main/java/com/ankurm/observability/OrderController.java))
|
|
|
|
Next: [2. The Observation API and @Observed](02-observation-api.md) -- where the same request
|
|
that produced this metric turns out, on its own, to produce only half the trace you'd expect.
|