Files
otel-quarkus-demo/CLAUDE.md
2026-05-29 16:17:38 +02:00

40 lines
4.0 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project
Quarkus 3.35 / Java 21 demo app (`otel-quarkus-demo`) that exercises a full observability stack: OpenTelemetry traces/metrics/logs via OTLP, Micrometer with both a Prometheus scrape endpoint and an OTLP push exporter, structured JSON logging, and SmallRye health checks. The OTLP endpoints in `application.properties` point at an in-cluster collector (`otel-collector-opentelemetry-collector.observability.svc.cluster.local`) — running locally without that collector means OTLP exporters will fail, but the app still serves requests and exposes `/q/metrics`.
## Commands
Use the Maven wrapper (`./mvnw`) — there is no `mvn` requirement.
- Dev mode (hot reload, dev UI at `/q/dev`): `./mvnw quarkus:dev`
- Build runnable app (fast-jar layout in `target/quarkus-app/`): `./mvnw package`
- Build container image (jib): `./mvnw package -Dquarkus.container-image.build=true`
- Run packaged app: `java -jar target/quarkus-app/quarkus-run.jar`
- Tests: `./mvnw test` (no tests exist yet; surefire/failsafe are configured via the Quarkus BOM)
- Single test once added: `./mvnw test -Dtest=ClassName#methodName`
The app listens on `:8080`. Key endpoints: `POST /api/orders`, `GET /api/orders`, `GET /api/orders/{id}`, `GET /api/inventory`, `GET /q/health`, `GET /q/metrics`.
## Architecture
Three classes under `src/main/java/com/demo/`, all part of a single REST surface:
- `OrderResource` — JAX-RS resource at `/api`. Every request path manually builds a parent span (`processOrder`) and child spans (`validateOrder`, `checkInventory`, `processPayment`) using the injected OTel `Tracer`, sets span attributes, and records status/exceptions explicitly. It also lazily registers Micrometer meters (`orders` counter tagged by status, `orders_amount` counter, `order_processing_duration` timer with percentiles, `order_item_count` summary) on each call — the registry deduplicates, but be aware that meter definitions live alongside the request handler rather than in a separate config class. Two behaviors are intentional for demo signal: `Thread.sleep` calls simulate latency, and ~10% of orders throw a synthetic `RuntimeException` to generate error traces.
- `InventoryService``@ApplicationScoped` CDI bean. Seeds six products on `@PostConstruct` and registers one `inventory_level` Micrometer gauge per product (tagged `product=...`) bound to an `AtomicInteger`. Decrementing below 10 auto-restocks by 100 — keep this in mind when interpreting metric dips.
- `Order` — DTO with auto-generated id and computed `totalPrice`. The in-memory order store lives on `OrderResource` as a `CopyOnWriteArrayList` (non-persistent; cleared on restart).
Observability wiring is entirely in `application.properties`:
- OTLP traces/metrics/logs are exported to the collector via gRPC on `:4317`, plus a parallel HTTP push of Micrometer metrics to `:4318/v1/metrics`. Both are configured — changing one without the other leaves a divergent metrics pipeline.
- The trace sampler is `always_on` (demo only — switch to ratio-based in any real deployment).
- Console log format embeds `traceId`/`spanId` from MDC; `quarkus.log.console.json.enabled=false` despite the `quarkus-logging-json` dependency being present (toggle it on for Loki-friendly output).
## Conventions worth knowing
- Span lifecycle in `OrderResource` is manual (`spanBuilder().startSpan()` + `try/finally span.end()`). When adding new endpoints, follow the same pattern rather than relying on `@WithSpan` so attributes/status handling stays consistent.
- Meter names use snake_case (`orders_amount`, `order_processing_duration`, `inventory_level`); tags use snake_case too (`order.product`, `inventory.in_stock`). Match this when adding metrics so dashboards/PromQL stay uniform.
- The Dockerfile is a two-stage Maven → JRE-alpine build that copies the `target/quarkus-app/` fast-jar layout — `./mvnw package` must succeed before `docker build` will work.