spring-boot
- Measuring OpenTelemetry Overhead Without Fooling Yourself
What OpenTelemetry costs a Spring Boot app in MiB and CPU per order, and the proofs each test cell needed before its number counted.
- The Config I Measured Was Not the Config That Ran
A Spring Boot native image never got its telemetry config file, and optional: kept quiet. Plus a compose run that swapped the app before a load test.
- Spring Boot 4 Keeps a Tracer With Tracing Off
In Spring Boot 4, management.tracing.enabled=false binds to nothing. The replacement switches off export, not the Tracer bean.
- Counts Match, Dashboards Don't: OTel Agent vs Starter
Swapping the OTel Java agent for a starter, which native requires, kept every exact count. Names, units, labels and buckets moved. What breaks, per target.
- A Broken AOT Cache Still Serves 200
By default the JVM logs one error and keeps running when its AOT cache is broken, so a Leyden tier without AOTMode=on can measure plain java -jar.
- Same Builder, Different Binary
One GraalVM builder image, one banner on every build log, 18 native binaries. Twelve came out PIE and six didn't, and nobody had touched a linker option.
- The Flag Was Verified. The File Was Never Read.
Spring's process-aot writes its own native-image.properties over yours. A verified GraalVM flag sat in the repo for 43 days and never reached the build.
- Health 200, API 200, Prometheus 000
A GraalVM 25i4 bump made native /prometheus stop answering. The reflection gap was old; a new default turned a missing metric into a hang.
- The Falsifier That Never Fired
Spring should wedge at 256MB like Micronaut, or the r2dbc-pool theory is wrong. Ten hours later Spring wedged harder. Quarkus never noticed.
- Eighteen Requests for One Redirect
One 302 from a stub upstream, four HTTP client stacks, four bills: 18, 6, 3 and 1 requests. Two sensible defaults, multiplied.