Skip to content

Commit 52d027d

Browse files
committed
Add OpenTelemetry tracing example and logging configuration
- Implemented OpenTelemetry tracing in a new Java sample demonstrating Durable Task SDK usage. - Created orchestration and activities with tracing spans for order processing workflow. - Added logback configuration for logging output to the console.
1 parent 12a76f4 commit 52d027d

11 files changed

Lines changed: 735 additions & 0 deletions

File tree

.github/workflows/build-samples.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ jobs:
132132
- name: Build DTS - async-http-api
133133
run: cd samples/durable-task-sdks/java/async-http-api && chmod +x gradlew && ./gradlew build
134134

135+
- name: Build DTS - opentelemetry-tracing
136+
run: cd samples/durable-task-sdks/java/opentelemetry-tracing && chmod +x gradlew && ./gradlew build
137+
135138
# Durable Functions samples (Maven)
136139
- name: Build DF - HelloCities
137140
run: cd samples/durable-functions/java/HelloCities && mvn compile --batch-mode
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# OpenTelemetry Distributed Tracing
2+
3+
| | |
4+
|-|-|
5+
| **Language** | Java 21 |
6+
| **SDK** | Durable Task SDK |
7+
8+
This sample shows how to wire up [OpenTelemetry](https://opentelemetry.io/) with the Durable Task SDK for Java to visualize orchestration flows in [Jaeger](https://www.jaegertracing.io/). It demonstrates trace correlation across an orchestrator and activities so you can see the full distributed trace of an order-processing workflow.
9+
10+
## Prerequisites
11+
12+
- [Java 21](https://learn.microsoft.com/java/openjdk/download)
13+
- [Docker](https://www.docker.com/products/docker-desktop)
14+
15+
## Quick Run
16+
17+
### 1. Start the infrastructure (DTS emulator + Jaeger)
18+
19+
```bash
20+
docker compose up -d
21+
```
22+
23+
This launches:
24+
- **DTS Emulator** on `localhost:8080` (gRPC) and `localhost:8082` (Dashboard)
25+
- **Jaeger** on `localhost:16686` (UI), `localhost:4317` (OTLP gRPC), and `localhost:4318` (OTLP HTTP)
26+
27+
### 2. Run the sample
28+
29+
```bash
30+
./gradlew runOpenTelemetryTracingPattern
31+
```
32+
33+
This starts the worker, schedules an `OrderProcessingOrchestration`, and waits for it to complete.
34+
35+
## Viewing Traces
36+
37+
1. Open the Jaeger UI at **http://localhost:16686**
38+
2. Select the **durable-worker** service from the dropdown
39+
3. Click **Find Traces**
40+
4. Click on a trace to see the span tree — you'll see spans for each activity (`ValidateOrder`, `ProcessPayment`, `ShipOrder`, `SendNotification`)
41+
42+
![Jaeger search results showing activity traces](images/jaeger-search-results.png)
43+
44+
Click on any trace to see the span details, including service name, duration, and OpenTelemetry tags:
45+
46+
![Jaeger trace detail view with span metadata](images/jaeger-trace-detail.png)
47+
48+
You can also view the orchestration status in the DTS Dashboard at **http://localhost:8082**.
49+
50+
## What You'll See
51+
52+
The Jaeger UI shows traces for each activity in the orchestration, including timing and any errors. This helps you:
53+
54+
- Identify slow activities
55+
- See the sequential flow of function chaining
56+
- Correlate traces across distributed services
57+
- Debug failures with full context
58+
59+
## How It Works
60+
61+
The sample configures an OpenTelemetry `TracerProvider` with an OTLP/gRPC exporter that sends spans to Jaeger. Each activity creates a manual span using the tracer. The Durable Task SDK automatically propagates W3C trace context (`traceparent`/`tracestate`) when scheduling orchestrations, enabling end-to-end trace correlation.
62+
63+
Key configuration:
64+
65+
```java
66+
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
67+
.setEndpoint(otlpEndpoint)
68+
.build();
69+
70+
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
71+
.setResource(Resource.builder().put("service.name", "durable-worker").build())
72+
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
73+
.build();
74+
75+
OpenTelemetrySdk.builder()
76+
.setTracerProvider(tracerProvider)
77+
.buildAndRegisterGlobal();
78+
```
79+
80+
## Clean Up
81+
82+
```bash
83+
docker compose down
84+
```
85+
86+
## Learn More
87+
88+
- [Observability Guide](../../../../docs/observability.md)
89+
- [OpenTelemetry Java docs](https://opentelemetry.io/docs/languages/java/)
90+
- [Durable Task Scheduler Dashboard](https://learn.microsoft.com/azure/azure-functions/durable/durable-task-scheduler/durable-task-scheduler-dashboard)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
plugins {
2+
id 'java'
3+
id 'application'
4+
}
5+
6+
group 'io.durabletask'
7+
version = '0.1.0'
8+
9+
java {
10+
sourceCompatibility = JavaVersion.VERSION_21
11+
targetCompatibility = JavaVersion.VERSION_21
12+
}
13+
def grpcVersion = '1.78.0'
14+
def openTelemetryVersion = '1.58.0'
15+
base { archivesName = 'durabletask-samples' }
16+
17+
repositories {
18+
mavenLocal()
19+
mavenCentral()
20+
}
21+
22+
task runOpenTelemetryTracingPattern(type: JavaExec) {
23+
classpath = sourceSets.main.runtimeClasspath
24+
mainClass = 'io.durabletask.samples.OpenTelemetryTracingPattern'
25+
systemProperty 'logback.configurationFile', 'src/main/resources/logback-spring.xml'
26+
}
27+
28+
dependencies {
29+
implementation("com.microsoft:durabletask-client:1.7.0")
30+
implementation("com.microsoft:durabletask-azuremanaged:1.7.0")
31+
32+
// Logging dependencies
33+
implementation 'ch.qos.logback:logback-classic:1.5.32'
34+
implementation 'org.slf4j:slf4j-api:2.0.17'
35+
36+
// gRPC
37+
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
38+
implementation "io.grpc:grpc-stub:${grpcVersion}"
39+
runtimeOnly "io.grpc:grpc-netty-shaded:${grpcVersion}"
40+
implementation 'com.azure:azure-identity:1.18.2'
41+
42+
// OpenTelemetry
43+
implementation "io.opentelemetry:opentelemetry-api:${openTelemetryVersion}"
44+
implementation "io.opentelemetry:opentelemetry-sdk:${openTelemetryVersion}"
45+
implementation "io.opentelemetry:opentelemetry-exporter-otlp:${openTelemetryVersion}"
46+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
services:
2+
dts-emulator:
3+
image: mcr.microsoft.com/dts/dts-emulator:latest
4+
ports:
5+
- "8080:8080"
6+
- "8082:8082"
7+
8+
jaeger:
9+
image: jaegertracing/all-in-one:latest
10+
ports:
11+
- "16686:16686"
12+
- "4317:4317"
13+
- "4318:4318"
14+
environment:
15+
- COLLECTOR_OTLP_ENABLED=true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
4+
zipStoreBase=GRADLE_USER_HOME
5+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)