Skip to content

Commit 1ddc9c6

Browse files
committed
Implement tracing support for Durable Task SDKs
- Add trace-helper functions to manage OpenTelemetry spans for orchestrations, activities, and timers. - Introduce methods to start spans for new orchestrations, orchestration executions, task scheduling, and event handling. - Implement span error handling and status management. - Create protobuf messages for orchestration trace context. - Add tests to validate tracing functionality, including span creation, attribute verification, and error handling.
1 parent f20505c commit 1ddc9c6

13 files changed

Lines changed: 2111 additions & 26 deletions

File tree

package-lock.json

Lines changed: 81 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/durabletask-js/package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,21 @@
4242
"google-protobuf": "^3.21.2"
4343
},
4444
"devDependencies": {
45+
"@opentelemetry/api": "^1.9.0",
46+
"@opentelemetry/sdk-trace-base": "^1.25.0",
4547
"@types/google-protobuf": "^3.15.6",
4648
"@types/jest": "^29.5.1",
4749
"@types/node": "^18.16.1",
4850
"jest": "^29.5.0",
4951
"ts-jest": "^29.1.0",
5052
"typescript": "^5.0.4"
53+
},
54+
"peerDependencies": {
55+
"@opentelemetry/api": "^1.4.0"
56+
},
57+
"peerDependenciesMeta": {
58+
"@opentelemetry/api": {
59+
"optional": true
60+
}
5161
}
52-
}
62+
}

packages/durabletask-js/src/client/client.ts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ import { Logger, ConsoleLogger } from "../types/logger.type";
2929
import { StartOrchestrationOptions } from "../task/options";
3030
import { mapToRecord } from "../utils/tags.util";
3131
import { populateTagsMap } from "../utils/pb-helper.util";
32+
import {
33+
startSpanForNewOrchestration,
34+
startSpanForEventRaisedFromClient,
35+
setSpanError,
36+
setSpanOk,
37+
endSpan,
38+
} from "../tracing";
3239

3340
// Re-export MetadataGenerator for backward compatibility
3441
export { MetadataGenerator } from "../utils/grpc-helper.util";
@@ -218,15 +225,26 @@ export class TaskHubGrpcClient {
218225

219226
populateTagsMap(req.getTagsMap(), tags);
220227

228+
// Create a tracing span for the new orchestration (if OTEL is available)
229+
const span = startSpanForNewOrchestration(req);
230+
221231
this._logger.info(`Starting new ${name} instance with ID = ${req.getInstanceid()}${effectiveVersion ? ` (version: ${effectiveVersion})` : ""}`);
222232

223-
const res = await callWithMetadata<pb.CreateInstanceRequest, pb.CreateInstanceResponse>(
224-
this._stub.startInstance.bind(this._stub),
225-
req,
226-
this._metadataGenerator,
227-
);
233+
try {
234+
const res = await callWithMetadata<pb.CreateInstanceRequest, pb.CreateInstanceResponse>(
235+
this._stub.startInstance.bind(this._stub),
236+
req,
237+
this._metadataGenerator,
238+
);
228239

229-
return res.getInstanceid();
240+
setSpanOk(span);
241+
return res.getInstanceid();
242+
} catch (e: any) {
243+
setSpanError(span, e);
244+
throw e;
245+
} finally {
246+
endSpan(span);
247+
}
230248
}
231249

232250
/**
@@ -376,13 +394,25 @@ export class TaskHubGrpcClient {
376394

377395
req.setInput(i);
378396

397+
// Create a tracing span for the raised event (if OTEL is available)
398+
const span = startSpanForEventRaisedFromClient(eventName, instanceId);
399+
379400
this._logger.info(`Raising event '${eventName}' for instance '${instanceId}'`);
380401

381-
await callWithMetadata<pb.RaiseEventRequest, pb.RaiseEventResponse>(
382-
this._stub.raiseEvent.bind(this._stub),
383-
req,
384-
this._metadataGenerator,
385-
);
402+
try {
403+
await callWithMetadata<pb.RaiseEventRequest, pb.RaiseEventResponse>(
404+
this._stub.raiseEvent.bind(this._stub),
405+
req,
406+
this._metadataGenerator,
407+
);
408+
409+
setSpanOk(span);
410+
} catch (e: any) {
411+
setSpanError(span, e);
412+
throw e;
413+
} finally {
414+
endSpan(span);
415+
}
386416
}
387417

388418
/**

packages/durabletask-js/src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,16 @@ export { ReplaySafeLogger, ReplayContext } from "./types/replay-safe-logger";
9292

9393
// Versioning utilities
9494
export { compareVersions } from "./utils/versioning.util";
95+
96+
// Distributed Tracing (OpenTelemetry)
97+
export {
98+
TRACER_NAME,
99+
DurableTaskAttributes,
100+
TaskType,
101+
createSpanName,
102+
createTimerSpanName,
103+
getOtelApi,
104+
getTracer,
105+
OrchestrationSpanInfo,
106+
startSpanForEventRaisedFromClient,
107+
} from "./tracing";

packages/durabletask-js/src/orchestration/history-event.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ export interface ExecutionStartedEvent extends HistoryEventBase {
8989
parentInstance?: ParentInstanceInfo;
9090
scheduledStartTimestamp?: Date;
9191
tags?: Record<string, string>;
92+
/** The parent trace context for distributed tracing (W3C Trace Context). */
93+
parentTraceContext?: TraceContext;
94+
/** The span ID assigned to this orchestration execution for replay continuity. */
95+
orchestrationSpanId?: string;
9296
}
9397

9498
/**
@@ -151,6 +155,8 @@ export interface TaskScheduledEvent extends HistoryEventBase {
151155
version?: string;
152156
input?: string;
153157
tags?: Record<string, string>;
158+
/** The parent trace context for distributed tracing (W3C Trace Context). */
159+
parentTraceContext?: TraceContext;
154160
}
155161

156162
/**
@@ -181,6 +187,8 @@ export interface SubOrchestrationInstanceCreatedEvent extends HistoryEventBase {
181187
instanceId?: string;
182188
input?: string;
183189
tags?: Record<string, string>;
190+
/** The parent trace context for distributed tracing (W3C Trace Context). */
191+
parentTraceContext?: TraceContext;
184192
}
185193

186194
/**

0 commit comments

Comments
 (0)