Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ of them assume you have docker running on your local machine.

## Example modules:

- [OpenTelemetry Reference Application](reference-application)
- A comprehensive reference application demonstrating OpenTelemetry usage following the
[Getting Started Reference Application Specification](https://opentelemetry.io/docs/getting-started/reference-application-specification/).
- Includes traces, metrics, logs, manual instrumentation, Docker setup with collector, and multiple configuration approaches.
- [Using the SDK AutoConfiguration module](autoconfigure)
- This module contains a fully-functional example of using the autoconfigure
SDK extension module to configure the SDK using only environment
Expand Down
13 changes: 13 additions & 0 deletions reference-application/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM openjdk:17-jdk-slim

WORKDIR /app

# Copy the JAR file and agent
COPY build/libs/app.jar /app.jar
COPY build/agent/opentelemetry-javaagent.jar /opentelemetry-javaagent.jar

# Expose the port
EXPOSE 8080

# Run the application with the Java agent
ENTRYPOINT ["java", "-javaagent:/opentelemetry-javaagent.jar", "-jar", "/app.jar"]
183 changes: 183 additions & 0 deletions reference-application/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# OpenTelemetry Java Reference Application

This reference application demonstrates comprehensive OpenTelemetry usage in Java, following the [OpenTelemetry Getting Started Reference Application Specification](https://opentelemetry.io/docs/getting-started/reference-application-specification/).

## Features

This application showcases:

- **Traces**: Manual and automatic span creation, distributed tracing
- **Metrics**: Custom metrics, performance monitoring
- **Logs**: Structured logging with trace correlation
- **Multiple exporters**: Console, OTLP, file-based exports
- **Configuration**: Environment variables, programmatic setup, and declarative configuration
- **Docker support**: Complete setup with OpenTelemetry Collector

## Application Overview

The reference application is a dice rolling service that demonstrates OpenTelemetry capabilities using the **OpenTelemetry Java Agent** for automatic instrumentation and manual instrumentation examples:

### Endpoints

- `GET /rolldice` - Basic dice roll (returns random 1-6)
- `GET /rolldice?player=<name>` - Dice roll for a specific player
- `GET /rolldice?rolls=<n>` - Roll multiple dice
- `GET /fibonacci?n=<number>` - Calculate fibonacci (demonstrates computation tracing)
- `GET /health` - Health check endpoint
- `GET /metrics` - Prometheus metrics endpoint (when enabled)

### Scenarios Demonstrated

1. **Basic HTTP instrumentation**: Automatic span creation for HTTP requests
2. **Manual instrumentation**: Custom spans for business logic
3. **Error handling**: Error span recording and exception tracking
4. **Custom metrics**: Performance counters, histograms, gauges
5. **Baggage propagation**: Cross-cutting concerns
6. **Resource detection**: Automatic resource attribute detection

## Quick Start

### Prerequisites

- Java 17 or later
- Docker and Docker Compose (for collector setup)

### Running with Console Output

```shell
# Build the application with the Java agent
../gradlew bootJar

# Run with the Java agent for automatic instrumentation
java -javaagent:build/agent/opentelemetry-javaagent.jar -jar build/libs/app.jar
```

Then test the endpoints:
```shell
curl http://localhost:8080/rolldice
curl http://localhost:8080/rolldice?player=alice
curl http://localhost:8080/fibonacci?n=10
```

### Running with OpenTelemetry Collector

```shell
# Build the application
../gradlew bootJar

# Start the collector and application
docker-compose up --build
```

This will:
- Start the reference application on port 8080
- Start OpenTelemetry Collector on port 4317/4318
- Export telemetry data to the collector
- Output structured telemetry data to console

## Configuration

The application supports multiple configuration approaches:

### Environment Variables

```shell
export OTEL_SERVICE_NAME=dice-server
export OTEL_SERVICE_VERSION=1.0.0
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
```

### Java Agent Configuration

The application uses the OpenTelemetry Java Agent which automatically configures instrumentation based on environment variables and system properties. All standard OpenTelemetry configuration options are supported.

### Declarative Configuration

Use the included `otel-config.yaml` for file-based configuration:

```shell
export OTEL_EXPERIMENTAL_CONFIG_FILE=otel-config.yaml
```

## Understanding the Output

### Traces

The application creates spans for:
- HTTP requests (automatic)
- Business logic operations (manual)
- External calls and computations
- Error scenarios

### Metrics

The application reports:
- Request duration histograms
- Request counters by endpoint
- Error rates
- Custom business metrics (dice roll distributions)

### Logs

All logs include:
- Trace ID and Span ID for correlation
- Structured fields
- Different log levels
- Business context

## Development

### Building

```shell
../gradlew build
```

### Testing

```shell
../gradlew test
```

### Running locally

```shell
../gradlew bootRun
```

## Docker Images

The application can be built as a Docker image:

```shell
../gradlew bootBuildImage
```

## Troubleshooting

### Common Issues

1. **No telemetry data**: Check OTEL_* environment variables
2. **Connection issues**: Verify collector endpoint configuration
3. **Missing traces**: Ensure sampling is configured correctly

### Debugging

Enable debug logging:
```shell
export OTEL_JAVAAGENT_DEBUG=true
```

Or set logging level:
```shell
export LOGGING_LEVEL_IO_OPENTELEMETRY=DEBUG
```

## Learn More

- [OpenTelemetry Java Documentation](https://opentelemetry.io/docs/languages/java/)
- [OpenTelemetry Specification](https://opentelemetry.io/docs/specs/otel/)
- [Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/)
58 changes: 58 additions & 0 deletions reference-application/build.gradle.kts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot also add a test of the telemetry that is exported from the difference scenarios using https://github.com/open-telemetry/opentelemetry-java-examples/tree/main/telemetry-testing as an example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added comprehensive telemetry testing based on the telemetry-testing example. The implementation includes:

New telemetry test class (TelemetryTest):

  • Uses MockServer to capture OTLP requests on port 4318
  • Validates traces, metrics, and baggage for different scenarios
  • Tests dice rolling, fibonacci calculation, and health endpoints
  • Verifies span attributes, events, and hierarchical relationships

Test scenarios covered:

  • HTTP spans from automatic instrumentation
  • Custom spans (roll-dice, fibonacci-calculation, etc.)
  • Micrometer metrics export (dice_rolls_total, fibonacci_duration_seconds)
  • Baggage propagation with player names and request types
  • Span events and detailed attributes validation

Configuration:

  • Java Agent attached during tests with proper OTLP settings
  • MockServer setup identical to telemetry-testing example
  • Protobuf parsing for ExportTraceServiceRequest and ExportMetricsServiceRequest

Documentation:

  • Updated README with telemetry testing section
  • Created TELEMETRY-TESTING.md with detailed implementation guide
  • Examples show how to validate different telemetry aspects

The tests provide comprehensive validation that the reference application correctly generates and exports OpenTelemetry data for all scenarios.

Commit: a756f00

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import org.springframework.boot.gradle.plugin.SpringBootPlugin
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
id("java")
id("org.springframework.boot") version "3.5.6"
}

val moduleName by extra { "io.opentelemetry.examples.reference-application" }

repositories {
mavenCentral()
}

val agent = configurations.create("agent")

dependencies {
implementation(platform(SpringBootPlugin.BOM_COORDINATES))
implementation("io.opentelemetry:opentelemetry-api")

// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")

// OpenTelemetry Instrumentation - use logback appender for logs
implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0")

// Micrometer for additional metrics
implementation("io.micrometer:micrometer-registry-prometheus")

// Java agent
agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.20.1")

// Testing
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
}

val copyAgent = tasks.register<Copy>("copyAgent") {
from(agent.singleFile)
into(layout.buildDirectory.dir("agent"))
rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar")
}

tasks.named<BootJar>("bootJar") {
dependsOn(copyAgent)
archiveFileName = "app.jar"
}

tasks.withType<Test> {
useJUnitPlatform()
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
37 changes: 37 additions & 0 deletions reference-application/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
services:
dice-server:
build: .
ports:
- "8080:8080"
environment:
- OTEL_SERVICE_NAME=dice-server
- OTEL_SERVICE_VERSION=1.0.0
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
- OTEL_TRACES_EXPORTER=otlp
- OTEL_METRICS_EXPORTER=otlp
- OTEL_LOGS_EXPORTER=otlp
- OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
depends_on:
- otel-collector

otel-collector:
image: otel/opentelemetry-collector-contrib:latest
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
- "8889:8889" # Prometheus metrics
volumes:
- ./otel-collector-config.yaml:/etc/otelcol-contrib/otel-collector-config.yaml
command: ["--config=/etc/otelcol-contrib/otel-collector-config.yaml"]

prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
47 changes: 47 additions & 0 deletions reference-application/otel-collector-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318

processors:
batch:
memory_limiter:
limit_mib: 512

exporters:
logging:
loglevel: info
sampling_initial: 5
sampling_thereafter: 200

prometheus:
endpoint: "0.0.0.0:8889"
metric_expiration: 180m
enable_open_metrics: true

extensions:
health_check:
endpoint: 0.0.0.0:13133
pprof:
endpoint: 0.0.0.0:1777
zpages:
endpoint: 0.0.0.0:55679

service:
extensions: [health_check, pprof, zpages]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [logging]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [logging, prometheus]
logs:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [logging]
39 changes: 39 additions & 0 deletions reference-application/otel-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
file_format: 0.3

# Service configuration
resource:
attributes:
service.name: dice-server
service.version: 1.0.0
deployment.environment: local

# Tracer provider configuration
tracer_provider:
processors:
- batch:
exporter:
console: {}
sampler:
parent_based:
root:
always_on: {}

# Meter provider configuration
meter_provider:
readers:
- periodic:
exporter:
console: {}
interval: 30000

# Logger provider configuration
logger_provider:
processors:
- batch:
exporter:
console: {}

# Propagators
propagators:
- tracecontext
- baggage
Loading