Skip to content

Commit 26879a8

Browse files
authored
Add OpenTelemetry distributed tracing example for Azure Managed DTS (#95)
1 parent f20505c commit 26879a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4526
-306
lines changed

.github/workflows/codeql.yml

Lines changed: 0 additions & 66 deletions
This file was deleted.

examples/azure-managed-dts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,23 @@ import { Task } from "../src/task/task";
3535
// These values should be set as environment variables
3636
const endpoint = process.env.AZURE_DTS_ENDPOINT;
3737
const taskHubName = process.env.AZURE_DTS_TASKHUB;
38-
const connectionString = process.env.AZURE_DTS_CONNECTION_STRING;
38+
const connectionString = process.env.DURABLE_TASK_SCHEDULER_CONNECTION_STRING;
3939

4040
// Validate configuration
4141
if (!connectionString && (!endpoint || !taskHubName)) {
4242
logger.error(
43-
"Error: Either AZURE_DTS_CONNECTION_STRING or both AZURE_DTS_ENDPOINT and AZURE_DTS_TASKHUB must be set.",
43+
"Error: Either DURABLE_TASK_SCHEDULER_CONNECTION_STRING or both AZURE_DTS_ENDPOINT and AZURE_DTS_TASKHUB must be set.",
4444
);
4545
logger.info("\nUsage:");
4646
logger.info(" Option 1: Create a .env file in the examples directory (recommended):");
4747
logger.info(
48-
" AZURE_DTS_CONNECTION_STRING=Endpoint=https://myservice.durabletask.io;Authentication=DefaultAzure;TaskHub=myTaskHub",
48+
" DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://myservice.durabletask.io;Authentication=DefaultAzure;TaskHub=myTaskHub",
4949
);
5050
logger.info(" or");
5151
logger.info(" AZURE_DTS_ENDPOINT=https://myservice.durabletask.io");
5252
logger.info(" AZURE_DTS_TASKHUB=myTaskHub");
5353
logger.info("\n Option 2: Set environment variables directly");
54-
logger.info(" export AZURE_DTS_CONNECTION_STRING=...");
54+
logger.info(" export DURABLE_TASK_SCHEDULER_CONNECTION_STRING=...");
5555
process.exit(1);
5656
}
5757

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Configuration for running with the local DTS Emulator + Jaeger
2+
# Copy this file to .env: cp .env.emulator .env
3+
4+
# DTS Emulator connection string (no authentication required)
5+
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=http://localhost:8080;Authentication=None;TaskHub=default
6+
7+
# OTLP endpoint for trace export (Jaeger's OTLP HTTP receiver)
8+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

examples/azure-managed/.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# Option 1: Using connection string (recommended)
44
# Supported authentication types: DefaultAzure, ManagedIdentity, WorkloadIdentity,
55
# Environment, AzureCli, AzurePowerShell, VisualStudioCode, InteractiveBrowser, None
6-
AZURE_DTS_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub
6+
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub
77
# Option 2: Using explicit parameters (uses DefaultAzureCredential)
8-
# Uncomment these lines and comment out AZURE_DTS_CONNECTION_STRING above
8+
# Uncomment these lines and comment out DURABLE_TASK_SCHEDULER_CONNECTION_STRING above
99
# AZURE_DTS_ENDPOINT=https://your-scheduler.eastus.durabletask.io
1010
# AZURE_DTS_TASKHUB=your-taskhub

examples/azure-managed/README.md

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Distributed Tracing with Azure Managed Durable Task Scheduler
2+
3+
This example demonstrates **OpenTelemetry distributed tracing** with the Durable Task JavaScript SDK and Azure Managed Durable Task Scheduler (DTS). Traces are exported to [Jaeger](https://www.jaegertracing.io/) so you can visualize the full orchestration lifecycle as connected spans.
4+
5+
## What You'll See
6+
7+
When you run this example, the SDK automatically produces [W3C Trace Context](https://www.w3.org/TR/trace-context/) spans for every stage of a durable orchestration:
8+
9+
| Span | Kind | Description |
10+
|------|------|-------------|
11+
| `create_orchestration:<name>` | PRODUCER | Client scheduling a new orchestration |
12+
| `orchestration:<name>` | SERVER | Worker executing the orchestration |
13+
| `activity:<name>` (scheduling) | CLIENT | Orchestrator scheduling an activity |
14+
| `activity:<name>` (execution) | SERVER | Worker executing the activity |
15+
| `timer:<orchestrationName>` | INTERNAL | Timer created inside an orchestration |
16+
| `orchestration_event:<eventName>` | PRODUCER | Event raised to another orchestration |
17+
18+
All spans are linked via `traceparent` propagation, giving you a single end-to-end trace from the client all the way through parallel activity fan-out and back.
19+
20+
### Sample Trace in Jaeger
21+
22+
```
23+
create_orchestration:dataPipelineOrchestrator (PRODUCER)
24+
└─ orchestration:dataPipelineOrchestrator (SERVER)
25+
├─ activity:getDataSources (CLIENT → SERVER)
26+
├─ activity:fetchData ×4 (CLIENT → SERVER, parallel)
27+
├─ activity:transformData ×4 (CLIENT → SERVER, parallel)
28+
└─ activity:saveResults (CLIENT → SERVER)
29+
```
30+
31+
---
32+
33+
## Prerequisites
34+
35+
- **Node.js ≥ 22** (required by the monorepo)
36+
- **Docker** (for the DTS Emulator and Jaeger)
37+
- **npm** (for installing dependencies)
38+
39+
---
40+
41+
## Quick Start (Local with DTS Emulator)
42+
43+
### 1. Start the DTS Emulator and Jaeger
44+
45+
A `docker-compose.yml` is provided that starts both services:
46+
47+
```bash
48+
cd examples/azure-managed
49+
docker compose up -d
50+
```
51+
52+
This starts:
53+
54+
| Service | Port | Purpose |
55+
|---------|------|---------|
56+
| **DTS Emulator** | `8080` | Local gRPC endpoint (no authentication) |
57+
| **Jaeger UI** | `16686` | Trace visualization dashboard |
58+
| **Jaeger OTLP (HTTP)** | `4318` | OpenTelemetry trace receiver |
59+
| **Jaeger OTLP (gRPC)** | `4317` | OpenTelemetry trace receiver (gRPC) |
60+
61+
> **Tip:** You can also run just the DTS Emulator standalone:
62+
> ```bash
63+
> docker run -d --name dts-emulator -p 8080:8080 -p 8082:8082 \
64+
> mcr.microsoft.com/dts/dts-emulator:latest
65+
> ```
66+
67+
### 2. Configure Environment Variables
68+
69+
Copy the provided emulator configuration:
70+
71+
```bash
72+
cp .env.emulator .env
73+
```
74+
75+
This sets:
76+
77+
```env
78+
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=http://localhost:8080;Authentication=None;TaskHub=default
79+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
80+
```
81+
82+
### 3. Install OpenTelemetry Dependencies
83+
84+
From the **repository root**, install the required OTel packages:
85+
86+
```bash
87+
npm install --no-save \
88+
@opentelemetry/api \
89+
@opentelemetry/sdk-node \
90+
@opentelemetry/sdk-trace-base \
91+
@opentelemetry/exporter-trace-otlp-http \
92+
@opentelemetry/resources \
93+
@opentelemetry/semantic-conventions
94+
```
95+
96+
> **Note:** `@opentelemetry/api` is an optional peer dependency of `@microsoft/durabletask-js`. When it's installed, the SDK automatically produces distributed tracing spans — no code changes needed in your orchestrations or activities.
97+
98+
### 4. Build the SDK (if not already built)
99+
100+
```bash
101+
npm run build
102+
```
103+
104+
### 5. Run the Example
105+
106+
```bash
107+
npm run example -- ./examples/azure-managed/distributed-tracing.ts
108+
```
109+
110+
You should see output like:
111+
112+
```
113+
OpenTelemetry SDK started – exporting traces to http://localhost:4318
114+
115+
=== Sequence Orchestration ===
116+
Scheduled: abc123
117+
Completed – result: ["Hello, Tokyo!","Hello, Seattle!","Hello, London!"]
118+
119+
=== Data Pipeline Orchestration ===
120+
Scheduled: def456
121+
Completed – result: {"sourcesProcessed":4,"resultsSaved":4,"data":["transformed(data-from-users-api)",...]}
122+
123+
=== All orchestrations completed! ===
124+
Open Jaeger UI at http://localhost:16686 and search for service "durabletask-js-tracing-example" to view traces.
125+
```
126+
127+
### 6. View Traces in Jaeger
128+
129+
1. Open [http://localhost:16686](http://localhost:16686) in your browser.
130+
2. Select the service **`durabletask-js-tracing-example`** from the dropdown.
131+
3. Click **Find Traces**.
132+
4. Click on a trace to explore the span waterfall.
133+
134+
---
135+
136+
## Running Against Azure Managed DTS (Cloud)
137+
138+
To run this example against a real Azure Managed Durable Task Scheduler endpoint instead of the local emulator:
139+
140+
### 1. Create a `.env` file
141+
142+
```env
143+
# Option A: Connection string
144+
DURABLE_TASK_SCHEDULER_CONNECTION_STRING=Endpoint=https://your-scheduler.eastus.durabletask.io;Authentication=DefaultAzure;TaskHub=your-taskhub
145+
146+
# Option B: Explicit parameters (uses DefaultAzureCredential)
147+
# AZURE_DTS_ENDPOINT=https://your-scheduler.eastus.durabletask.io
148+
# AZURE_DTS_TASKHUB=your-taskhub
149+
150+
# OTLP endpoint (Jaeger, Azure Monitor, Aspire Dashboard, etc.)
151+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
152+
```
153+
154+
### 2. Authenticate
155+
156+
Make sure you're logged in via Azure CLI:
157+
158+
```bash
159+
az login
160+
```
161+
162+
### 3. Run
163+
164+
```bash
165+
npm run example -- ./examples/azure-managed/distributed-tracing.ts
166+
```
167+
168+
---
169+
170+
## Using Azure Monitor / Application Insights
171+
172+
To export traces to **Azure Monitor** instead of Jaeger, replace the OTLP exporter with the Azure Monitor exporter:
173+
174+
```bash
175+
npm install --no-save @azure/monitor-opentelemetry-exporter
176+
```
177+
178+
Then modify the OpenTelemetry setup in `distributed-tracing.ts`:
179+
180+
```typescript
181+
import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";
182+
183+
const traceExporter = new AzureMonitorTraceExporter({
184+
connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
185+
});
186+
```
187+
188+
---
189+
190+
## DTS Emulator Docker Image Reference
191+
192+
| Property | Value |
193+
|----------|-------|
194+
| **Image** | `should be mcr.microsoft.com/dts/dts-emulator:latest` |
195+
| **gRPC Port** | `8080` |
196+
| **Dashboard Port** | `8082` |
197+
| **Authentication** | `None` (no credentials required) |
198+
| **Connection String** | `Endpoint=http://localhost:8080;Authentication=None;TaskHub=default` |
199+
200+
### Running the Emulator Standalone
201+
202+
```bash
203+
docker run -d \
204+
--name dts-emulator \
205+
-p 8080:8080 \
206+
-p 8082:8082 \
207+
should be mcr.microsoft.com/dts/dts-emulator:latest
208+
```
209+
210+
### Stopping the Emulator
211+
212+
```bash
213+
docker stop dts-emulator && docker rm dts-emulator
214+
```
215+
216+
---
217+
218+
## How Distributed Tracing Works
219+
220+
The Durable Task JavaScript SDK uses OpenTelemetry as an **optional peer dependency**. When `@opentelemetry/api` is installed and a `TracerProvider` is registered, the SDK automatically:
221+
222+
1. **Creates spans** for orchestration scheduling, execution, activity scheduling/execution, timers, and events.
223+
2. **Propagates W3C `traceparent`** through the gRPC protocol so that spans from the client, orchestrator, and activities are all linked in a single trace.
224+
3. **Handles replay correctly** – on orchestration replay, the SDK carries forward the original span ID so all replay iterations correlate to the same logical orchestration execution.
225+
226+
The tracer is registered under the name **`Microsoft.DurableTask`**, and spans include semantic attributes like:
227+
228+
- `durabletask.type``orchestration`, `activity`, `timer`, `event`, etc.
229+
- `durabletask.task.name` – The function name.
230+
- `durabletask.task.instance_id` – The orchestration instance ID.
231+
- `durabletask.task.task_id` – The sequential task ID within an orchestration.
232+
233+
---
234+
235+
## Cleanup
236+
237+
```bash
238+
cd examples/azure-managed
239+
docker compose down
240+
```
241+
242+
---
243+
244+
## Files in This Example
245+
246+
| File | Description |
247+
|------|-------------|
248+
| `distributed-tracing.ts` | Main example – OTel setup + orchestrations |
249+
| `docker-compose.yml` | DTS Emulator + Jaeger stack |
250+
| `.env.emulator` | Pre-configured env vars for the local emulator |
251+
| `.env.example` | Template for Azure Managed DTS (cloud) |
252+
| `index.ts` | Basic example (no tracing) |

0 commit comments

Comments
 (0)