Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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"]
80 changes: 80 additions & 0 deletions reference-application/E2E-TEST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# End-to-End Test

This directory contains an end-to-end test (`test-e2e.sh`) that validates the complete OpenTelemetry reference application stack.

## What it tests

The test verifies:
1. **Application functionality**: All endpoints return correct responses
2. **OpenTelemetry integration**: Telemetry data is generated and exported
3. **Collector functionality**: OTLP data is received and processed
4. **Prometheus integration**: Metrics are scraped and available
5. **Docker Compose setup**: All services start and work together

## Running the test

### Prerequisites

- Docker
- Docker Compose (or `docker compose`)
- curl
- jq

### Execution

```bash
# Via Gradle
../gradlew e2eTest

# Directly
./test-e2e.sh

# Dry-run (validation only)
./test-e2e.sh --dry-run
```

## Test flow

1. **Setup**: Cleans any existing containers and builds fresh images
2. **Start services**: Runs `docker-compose up --build -d`
3. **Wait for readiness**: Polls health endpoints until services are ready
4. **Functional tests**: Tests all application endpoints
5. **Telemetry validation**: Verifies OpenTelemetry data collection
6. **Integration tests**: Checks collector and Prometheus functionality
7. **Cleanup**: Stops and removes all containers and volumes

## What's tested

### Application Endpoints
- `GET /rolldice` - Basic dice rolling
- `GET /rolldice?player=testuser` - Parameterized requests
- `GET /rolldice?rolls=3` - Multiple dice rolls
- `GET /fibonacci?n=10` - Computational example
- `GET /health` - Health check
- `GET /actuator/prometheus` - Metrics export

### OpenTelemetry Integration
- Java Agent instrumentation
- Custom span creation
- Metrics generation
- Log correlation
- OTLP export to collector

### Infrastructure
- OpenTelemetry Collector OTLP ingestion
- Prometheus metrics scraping
- Service networking and dependencies

## Using in CI/CD

This test can be integrated into CI/CD pipelines to ensure the reference application works correctly in a production-like environment.

Example GitHub Actions usage:
```yaml
- name: Run end-to-end test
run: |
cd reference-application
./test-e2e.sh
```

The test automatically handles cleanup and provides clear success/failure indicators.
205 changes: 205 additions & 0 deletions reference-application/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# 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
```

### End-to-End Testing

Run the comprehensive end-to-end test that verifies the complete OpenTelemetry stack:

```shell
# Run via Gradle
../gradlew e2eTest

# Or run directly
./test-e2e.sh
```

This test:
- Builds and starts all services using `docker-compose up --build`
- Waits for services to be ready (application, collector, Prometheus)
- Tests all application endpoints
- Verifies OpenTelemetry data collection and export
- Validates Prometheus metric scraping
- Cleans up resources automatically

For detailed information about the end-to-end test, see [E2E-TEST.md](E2E-TEST.md).

### 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/)
62 changes: 62 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,62 @@
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")

// 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()
}

task("e2eTest", Exec::class) {
group = "verification"
description = "Run end-to-end test using docker-compose"
commandLine("./test-e2e.sh")
dependsOn("bootJar")
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
Loading