feat: distributed tracing with OpenTelemetry + Jaeger#4
Conversation
Agent-Logs-Url: https://github.com/vitorhugo-java/SpringBoot-JobApplyTracker/sessions/609122bb-e5ee-4c48-ad22-bec8f3d6a72f Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces distributed tracing and log correlation for the Spring Boot backend using Micrometer Tracing with an OpenTelemetry bridge, exporting traces over OTLP to Jaeger, and adds local Docker Compose infrastructure to run the stack.
Changes:
- Add tracing + OTLP exporter dependencies and management configuration for sampling and endpoint.
- Add manual child spans around key service operations (application creation, login, token refresh).
- Add Jaeger to
docker-compose.yml, add container build viabackend/Dockerfile, and add log correlation vialogback-spring.xml.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| docker-compose.yml | Adds MariaDB + Jaeger + app services for local tracing setup |
| backend/pom.xml | Adds actuator, Micrometer tracing bridge, OTLP exporter, Prometheus registry |
| backend/src/main/resources/application.yml | Configures management tracing sampling and OTLP endpoint |
| backend/src/main/resources/logback-spring.xml | Adds MDC-based traceId/spanId log pattern |
| backend/src/main/java/com/jobtracker/service/ApplicationService.java | Adds manual span around create operation with a trace tag |
| backend/src/main/java/com/jobtracker/service/AuthService.java | Adds manual spans around login and refresh flows |
| backend/src/test/java/com/jobtracker/JobTrackerApplicationTests.java | Disables tracing sampling during context-load test |
| backend/Dockerfile | Adds multi-stage build for backend container image |
| .gitignore | Ignores .env |
| .env.example | Provides example env vars for local runs |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return applicationMapper.toResponse(applicationRepository.save(app)); | ||
| Span span = tracer.nextSpan().name("create-application").start(); | ||
| try (Tracer.SpanInScope ignored = tracer.withSpan(span)) { | ||
| span.tag("vacancy", request.vacancyName() != null ? request.vacancyName() : "unknown"); |
There was a problem hiding this comment.
Tagging spans with the free-form vacancyName risks very high-cardinality trace attributes (and potentially sensitive user-entered data), which can significantly increase tracing storage/query costs. Consider removing this tag, tagging a stable identifier instead, and/or truncating/normalizing the value; also the null-check is redundant since vacancyName is @NotBlank in ApplicationRequest.
| span.tag("vacancy", request.vacancyName() != null ? request.vacancyName() : "unknown"); |
…d update Jaeger image version
|
@copilot apply changes based on the comments in this thread |
- Resolve all 6 conflicted files (pom.xml, application.yml, logback-spring.xml, AuthService.java, Dockerfile, docker-compose.yml) - Remove 4 leftover merge-artifact files (docker-compose_BACKUP/BASE/LOCAL/REMOTE) - Remove all .orig backup files - pom.xml: keep tracing deps + logstash + testcontainers (both sides merged) - application.yml: single management block with tracing/OTLP config + springdoc groups - logback-spring.xml: origin/main structure with traceId/spanId added to CONSOLE pattern - AuthService: do not call span.error() for BadCredentialsException; fix refresh() to correctly return RefreshResponse instead of AuthResponse - ApplicationService: remove high-cardinality vacancy tag from span - Dockerfile: use maven:3.9-eclipse-temurin-21 image; add non-root user; root-level paths - docker-compose.yml: full merge – Jaeger 1.57.0 + Prometheus/Grafana; require DB passwords via :? syntax; env-var driven JWT_SECRET - ApplicationServiceTest/AuthServiceTest: add @mock(RETURNS_DEEP_STUBS) Tracer - application-test.yml: disable tracing (probability=0.0) in test profile Agent-Logs-Url: https://github.com/vitorhugo-java/SpringBoot-JobApplyTracker/sessions/1f21e07a-4b0e-477b-b5db-c700a3631326 Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com>
All conflicts resolved and reviewer feedback applied in commit
|
Adds end-to-end distributed tracing to the Spring Boot app using the Micrometer→OpenTelemetry bridge, exporting spans to Jaeger via OTLP gRPC. Every inbound HTTP request produces a trace spanning the security filter, controller, service, repository, and JDBC layers automatically.
Dependencies
spring-boot-starter-actuator— activates Micrometer Observationsmicrometer-tracing-bridge-otel— bridges MicrometerTracerto OTel SDKopentelemetry-exporter-otlp— OTLP gRPC export to Jaegermicrometer-registry-prometheus— Prometheus metrics coexistence (unchanged behaviour)logstash-logback-encoder— structured JSON logging for productionAll versions managed by Spring Boot 3.2.5 BOM — no explicit pins needed.
Manual spans
Critical business operations are wrapped with named child spans for granular visibility:
Covered:
create-application(ApplicationService),loginandtoken-refresh(AuthService). No PII or tokens tagged.BadCredentialsExceptionis intentionally excluded fromspan.error()to avoid inflating error rates with expected authentication failures.Log correlation
logback-spring.xmlinjectstraceIdandspanIdinto every log line via MDC — automatically populated by the bridge. Uses Spring profile-based configuration:prodprofile: structured JSON viaLogstashEncoder(MDC fields included automatically)!prodprofile: human-readable console output with inline trace correlation:DEBUG logging for
com.jobtrackerandorg.hibernate.SQLis scoped to the non-production profile only.Configuration
management.tracing.sampling.probabilitydefaults to1.0, overridable viaTRACING_SAMPLING_PROBABILITYenv var for production tuningmanagement.otlp.tracing.endpointdefaults tohttp://localhost:4317, overridable viaOTEL_EXPORTER_OTLP_ENDPOINThealth,info,metrics,prometheusDocker
docker-compose.yml— full stack: Jaeger (jaegertracing/all-in-one:1.57.0, pinned) withCOLLECTOR_OTLP_ENABLED=true; UI at:16686, OTLP at:4317; Prometheus and Grafana retainedDockerfile— multi-stage build usingmaven:3.9-eclipse-temurin-21; runs as a non-root user (appuser) for container hardening; exposes management port8081with a health checkDB_PASSWORD,DB_ROOT_PASSWORD, andJWT_SECRETare required (no insecure defaults) via Docker Compose:?syntax.env.exampleprovided;.envadded to.gitignore