Spring Boot 3.5.9 application with OpenTelemetry instrumentation using the OpenTelemetry SDK Integration approach.
This example uses OpenTelemetry SDK Integration (production-ready):
- Dependency:
opentelemetry-spring-boot-starter - Direct OpenTelemetry API access
- Explicit dependency management via BOM
- Compatible with Spring Boot 2.7+ and 3.x
- ✅ HTTP requests and responses (Spring MVC)
- ✅ Database queries (JDBC/JPA) and connection pools
- ✅ JVM metrics (memory, threads, GC)
- ✅ Distributed trace propagation (W3C)
- ✅ Custom business metrics via Micrometer
For deeper application-level tracing (controller methods, service methods), consider:
- Manual
@WithSpanannotations, OR - OpenTelemetry Java Agent for zero-code instrumentation
- Docker Desktop or Docker Engine with Compose
- Base14 Scout credentials (setup guide)
- Java 25+ (only for local development without Docker)
# Clone and navigate
git clone https://github.com/base-14/examples.git
cd examples/java/spring-boot-java25-postgresql
# Set Base14 Scout credentials as environment variables
export SCOUT_ENDPOINT=https://your-tenant.base14.io/v1/traces
export SCOUT_CLIENT_ID=your_client_id
export SCOUT_CLIENT_SECRET=your_client_secret
export SCOUT_TOKEN_URL=https://your-tenant.base14.io/oauth/token
# Start application (PostgreSQL + Spring Boot + OTel Collector)
docker-compose up --build -d
# Verify it's running
curl http://localhost:8080/actuator/health
curl http://localhost:8080/users/testMessageThe app runs on port 8080, PostgreSQL on 5432, OTel Collector on 4317/4318.
The OpenTelemetry Collector requires Base14 Scout credentials to export
telemetry data. Set these before running docker-compose up:
| Variable | Required | Description |
|---|---|---|
SCOUT_ENDPOINT |
Yes | Base14 Scout OTLP endpoint |
SCOUT_CLIENT_ID |
Yes | OAuth2 client ID from Base14 Scout |
SCOUT_CLIENT_SECRET |
Yes | OAuth2 client secret from Base14 Scout |
SCOUT_TOKEN_URL |
Yes | OAuth2 token endpoint |
Example:
export SCOUT_ENDPOINT=https://your-tenant.base14.io/v1/traces
export SCOUT_CLIENT_ID=your_client_id
export SCOUT_CLIENT_SECRET=your_client_secret
export SCOUT_TOKEN_URL=https://your-tenant.base14.io/oauth/tokenSee the Base14 Collector Setup Guide for obtaining credentials.
| Variable | Default |
|---|---|
SPRING_APPLICATION_NAME |
java-spring-boot-otel |
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf |
OTEL_EXPORTER_OTLP_ENDPOINT |
http://otel-collector:4318 |
Automatically included in telemetry:
service.name=java-spring-boot-otel
service.namespace=base14
service.version=0.0.1-SNAPSHOT
deployment.environment=dev| Method | Endpoint | Description |
|---|---|---|
GET |
/users/ |
List all users |
POST |
/users/saveUser |
Create user |
PUT |
/users/{id} |
Update user |
DELETE |
/users/{id} |
Delete user |
GET |
/users/testMessage |
Test endpoint |
# Create user
curl -X POST http://localhost:8080/users/saveUser \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","address":"123 Main St"}'
# List users
curl http://localhost:8080/users/| Endpoint | Purpose |
|---|---|
/actuator/health |
Health status |
/actuator/metrics |
Metrics list |
/actuator/prometheus |
Prometheus format |
Requires PostgreSQL and OTel Collector running locally on standard ports.
./gradlew bootRun # Run application
./gradlew test # Run tests
./gradlew build # Build JARUpdate application.properties to use localhost:5432 for PostgreSQL.
docker-compose up --build # Build and start
docker-compose down # Stop all
docker-compose down -v # Stop and remove volumes
docker logs spring-app -f # View logs
docker-compose restart spring-service # Restart app onlyRun only PostgreSQL in Docker, app locally for quick iteration:
docker-compose up db -d # Start PostgreSQL only
./gradlew bootRun # Run app locally- HTTP requests (method, URL, status)
- Database queries (SQL statements)
- Exceptions and stack traces
- HTTP: Request count, duration, errors
- JVM: Memory, GC, threads
- Database: Connection pool, query duration
- Process: CPU, file descriptors
All logs include trace_id and span_id for correlation.
From build.gradle (BOM-managed):
implementation platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.23.0")
implementation "io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter"
implementation "io.micrometer:micrometer-tracing-bridge-otel"Configured via application.properties:
- Automatic instrumentation for JDBC, Spring WebMVC, and Logback
- OTLP exporter with HTTP/Protobuf protocol
- Always-on sampling (100%), 30-second metric export interval
- W3C trace context propagation
- Custom business metrics via Micrometer counters
docker ps | grep otel-collector # Check collector is running
docker logs otel-collector # View collector logsUse host.docker.internal not localhost when running app in Docker.
docker logs spring-app | grep -i otel # Check app logsVerify collector config exports to the correct backend.
docker-compose ps # Check PostgreSQL health
docker logs postgres-db # View PostgreSQL logsWait for PostgreSQL healthcheck to complete before starting the app.
In compose.yaml:
environment:
OTEL_LOG_LEVEL: DEBUGOr application.properties:
logging.level.io.opentelemetry=DEBUG| Component | Version |
|---|---|
| Spring Boot | 3.5.9 |
| OpenTelemetry Instrumentation | 2.23.0 |
| OpenTelemetry SDK | 1.55.0 |
| PostgreSQL | 17.7 |
| OTel Collector | 0.144.0 |
| Gradle | 9.2.1 |
| Java | 25 |
- Spring Boot Auto-Instrumentation Guide - Base14 documentation
- OpenTelemetry Java - OTel Java docs
- Spring Boot Actuator - Actuator reference
- Base14 Scout - Observability platform