Add observability: real OTLP metrics/traces to grafana/otel-lgtm, Docker Compose auto-wiring, and a dual-version (Boot 4.0 vs 4.1) proof of the new OTEL_* env var support
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).
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package com.ankurm.observability;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Companion app for docs/00-migrating-to-opentelemetry-starter.md. Run with `scripts/run.sh` --
|
||||
* Boot's Docker Compose support (compose.yaml, grafana/otel-lgtm) auto-wires the OTLP metrics,
|
||||
* traces and logs exporters with zero management.otlp.* properties in application.yml.
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ObservabilityApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ObservabilityApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ankurm.observability;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.aop.ObservedAspect;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Without this bean, @Observed is inert: Spring Boot's autoconfiguration wires up an
|
||||
* ObservationRegistry, but it does NOT register an ObservedAspect for you, even with
|
||||
* spring-boot-starter-aspectj (AspectJ weaver) on the classpath and Micrometer Tracing active.
|
||||
* See docs/output/03-observed-needs-explicit-bean.txt for the trace showing only the HTTP server
|
||||
* span before this bean existed, and docs/02-observation-api.md for the correction.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ObservationConfig {
|
||||
|
||||
@Bean
|
||||
ObservedAspect observedAspect(ObservationRegistry registry) {
|
||||
return new ObservedAspect(registry);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ankurm.observability;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.observation.annotation.Observed;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Real traffic source for docs/output/01-metrics-and-traces-in-lgtm.txt. Every call increments
|
||||
* a Micrometer counter (exported as an OTLP metric) and, via @Observed, opens a trace span --
|
||||
* one recording, two signals, exactly as described in
|
||||
* https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/observability/docs/02-observation-api.md
|
||||
*/
|
||||
@RestController
|
||||
class OrderController {
|
||||
|
||||
private final Counter ordersPlaced;
|
||||
|
||||
OrderController(MeterRegistry registry) {
|
||||
this.ordersPlaced = Counter.builder("orders.placed")
|
||||
.description("Number of orders placed")
|
||||
.tag("channel", "web")
|
||||
.register(registry);
|
||||
}
|
||||
|
||||
@Observed(name = "place-order", contextualName = "order-controller#placeOrder")
|
||||
@PostMapping("/orders/{id}")
|
||||
Map<String, Object> placeOrder(@PathVariable String id) throws InterruptedException {
|
||||
ordersPlaced.increment();
|
||||
// Simulate a bit of real work so the trace span has non-zero duration.
|
||||
Thread.sleep(ThreadLocalRandom.current().nextInt(5, 40));
|
||||
return Map.of("id", id, "status", "placed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: order-service
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health
|
||||
metrics:
|
||||
tags:
|
||||
application: ${spring.application.name}
|
||||
# No management.otlp.* export properties here on purpose -- see docs/03-otel-env-vars.md.
|
||||
# In development, Boot's Docker Compose support (see compose.yaml) auto-configures the OTLP
|
||||
# export endpoints for metrics, traces and logs the moment it detects the grafana/otel-lgtm
|
||||
# image, without a single management.otlp.* property in this file.
|
||||
# management.tracing.sampling.probability defaults to 0.10 -- see docs/output/02-low-sampling-demo.txt
|
||||
# for what that does to a short burst of local traffic, and the "fulltrace" profile below for the fix.
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: fulltrace
|
||||
management:
|
||||
tracing:
|
||||
sampling:
|
||||
probability: 1.0
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.ankurm.observability;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
* Docker Compose support is off by default in tests (Boot skips it under `mvn test`), so this
|
||||
* just confirms the application context -- including the OpenTelemetry starter's autoconfiguration
|
||||
* and the explicit ObservedAspect bean in ObservationConfig -- wires up cleanly without a running
|
||||
* collector. The real, docker-backed proof (metrics and traces actually landing in a live Grafana
|
||||
* LGTM stack) is in scripts/run-all.sh and docs/output/, which need Docker and take real wall time
|
||||
* -- not something to run on every `mvn test`.
|
||||
*/
|
||||
@SpringBootTest
|
||||
class ObservabilityApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user