@temporalio/interceptors-opentelemetry-v2 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +12 -0
- package/lib/client/index.d.ts +26 -0
- package/lib/client/index.js +185 -0
- package/lib/client/index.js.map +1 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +32 -0
- package/lib/index.js.map +1 -0
- package/lib/instrumentation.d.ts +58 -0
- package/lib/instrumentation.js +152 -0
- package/lib/instrumentation.js.map +1 -0
- package/lib/plugin.d.ts +31 -0
- package/lib/plugin.js +66 -0
- package/lib/plugin.js.map +1 -0
- package/lib/worker/index.d.ts +69 -0
- package/lib/worker/index.js +222 -0
- package/lib/worker/index.js.map +1 -0
- package/lib/workflow/context-manager.d.ts +10 -0
- package/lib/workflow/context-manager.js +67 -0
- package/lib/workflow/context-manager.js.map +1 -0
- package/lib/workflow/definitions.d.ts +127 -0
- package/lib/workflow/definitions.js +92 -0
- package/lib/workflow/definitions.js.map +1 -0
- package/lib/workflow/id-generator.d.ts +8 -0
- package/lib/workflow/id-generator.js +30 -0
- package/lib/workflow/id-generator.js.map +1 -0
- package/lib/workflow/index.d.ts +51 -0
- package/lib/workflow/index.js +252 -0
- package/lib/workflow/index.js.map +1 -0
- package/lib/workflow/performance-polyfill.d.ts +16 -0
- package/lib/workflow/performance-polyfill.js +29 -0
- package/lib/workflow/performance-polyfill.js.map +1 -0
- package/lib/workflow/runtime.d.ts +1 -0
- package/lib/workflow/runtime.js +14 -0
- package/lib/workflow/runtime.js.map +1 -0
- package/lib/workflow/span-exporter.d.ts +9 -0
- package/lib/workflow/span-exporter.js +56 -0
- package/lib/workflow/span-exporter.js.map +1 -0
- package/lib/workflow/workflow-imports-impl.d.ts +7 -0
- package/lib/workflow/workflow-imports-impl.js +17 -0
- package/lib/workflow/workflow-imports-impl.js.map +1 -0
- package/lib/workflow/workflow-imports.d.ts +16 -0
- package/lib/workflow/workflow-imports.js +25 -0
- package/lib/workflow/workflow-imports.js.map +1 -0
- package/lib/workflow-interceptors.d.ts +3 -0
- package/lib/workflow-interceptors.js +12 -0
- package/lib/workflow-interceptors.js.map +1 -0
- package/package.json +78 -0
- package/src/client/index.ts +220 -0
- package/src/index.ts +14 -0
- package/src/instrumentation.ts +159 -0
- package/src/plugin.ts +86 -0
- package/src/worker/index.ts +264 -0
- package/src/workflow/context-manager.ts +53 -0
- package/src/workflow/definitions.ts +145 -0
- package/src/workflow/id-generator.ts +30 -0
- package/src/workflow/index.ts +312 -0
- package/src/workflow/performance-polyfill.ts +31 -0
- package/src/workflow/runtime.ts +12 -0
- package/src/workflow/span-exporter.ts +60 -0
- package/src/workflow/workflow-imports-impl.ts +14 -0
- package/src/workflow/workflow-imports.ts +39 -0
- package/src/workflow-interceptors.ts +14 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import { createTraceState } from '@opentelemetry/api';
|
|
3
|
+
import type { Resource } from '@opentelemetry/resources';
|
|
4
|
+
import type { ReadableSpan, SpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
5
|
+
import type * as nexus from 'nexus-rpc';
|
|
6
|
+
import type { Context as ActivityContext } from '@temporalio/activity';
|
|
7
|
+
import { CompleteAsyncError } from '@temporalio/common';
|
|
8
|
+
import type {
|
|
9
|
+
Next,
|
|
10
|
+
ActivityInboundCallsInterceptor,
|
|
11
|
+
ActivityOutboundCallsInterceptor,
|
|
12
|
+
NexusInboundCallsInterceptor,
|
|
13
|
+
NexusOutboundCallsInterceptor,
|
|
14
|
+
NexusStartOperationInput,
|
|
15
|
+
NexusStartOperationOutput,
|
|
16
|
+
NexusCancelOperationInput,
|
|
17
|
+
InjectedSink,
|
|
18
|
+
GetLogAttributesInput,
|
|
19
|
+
GetMetricTagsInput,
|
|
20
|
+
ActivityExecuteInput,
|
|
21
|
+
} from '@temporalio/worker';
|
|
22
|
+
import {
|
|
23
|
+
instrument,
|
|
24
|
+
extractContextFromHeaders,
|
|
25
|
+
extractContextFromNexusHeaders,
|
|
26
|
+
WORKFLOW_ID_ATTR_KEY,
|
|
27
|
+
RUN_ID_ATTR_KEY,
|
|
28
|
+
ACTIVITY_ID_ATTR_KEY,
|
|
29
|
+
NEXUS_SERVICE_ATTR_KEY,
|
|
30
|
+
NEXUS_OPERATION_ATTR_KEY,
|
|
31
|
+
} from '../instrumentation';
|
|
32
|
+
import {
|
|
33
|
+
type OpenTelemetryWorkflowExporter,
|
|
34
|
+
type SerializableSpan,
|
|
35
|
+
SpanName,
|
|
36
|
+
SPAN_DELIMITER,
|
|
37
|
+
} from '../workflow/definitions';
|
|
38
|
+
|
|
39
|
+
export interface InterceptorOptions {
|
|
40
|
+
readonly tracer?: otel.Tracer;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Intercepts calls to start an Activity.
|
|
45
|
+
*
|
|
46
|
+
* Wraps the operation in an opentelemetry Span and links it to a parent Span context if one is
|
|
47
|
+
* provided in the Activity input headers.
|
|
48
|
+
*
|
|
49
|
+
* @experimental This interceptor is experimental and APIs may change without notice.
|
|
50
|
+
*/
|
|
51
|
+
export class OpenTelemetryActivityInboundInterceptor implements ActivityInboundCallsInterceptor {
|
|
52
|
+
protected readonly tracer: otel.Tracer;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
protected readonly ctx: ActivityContext,
|
|
56
|
+
options?: InterceptorOptions
|
|
57
|
+
) {
|
|
58
|
+
this.tracer = options?.tracer ?? otel.trace.getTracer('@temporalio/interceptor-activity');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async execute(input: ActivityExecuteInput, next: Next<ActivityInboundCallsInterceptor, 'execute'>): Promise<unknown> {
|
|
62
|
+
const context = extractContextFromHeaders(input.headers);
|
|
63
|
+
const spanName = `${SpanName.ACTIVITY_EXECUTE}${SPAN_DELIMITER}${this.ctx.info.activityType}`;
|
|
64
|
+
return await instrument({
|
|
65
|
+
tracer: this.tracer,
|
|
66
|
+
spanName,
|
|
67
|
+
fn: (span) => {
|
|
68
|
+
span.setAttribute(ACTIVITY_ID_ATTR_KEY, this.ctx.info.activityId);
|
|
69
|
+
if (this.ctx.info.inWorkflow) {
|
|
70
|
+
span.setAttribute(WORKFLOW_ID_ATTR_KEY, this.ctx.info.workflowExecution!.workflowId);
|
|
71
|
+
span.setAttribute(RUN_ID_ATTR_KEY, this.ctx.info.workflowExecution!.runId);
|
|
72
|
+
}
|
|
73
|
+
return next(input);
|
|
74
|
+
},
|
|
75
|
+
context,
|
|
76
|
+
acceptableErrors: (err) => err instanceof CompleteAsyncError,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Intercepts calls to emit logs and metrics from an Activity.
|
|
83
|
+
*
|
|
84
|
+
* Attach OpenTelemetry context tracing attributes to emitted log messages, if appropriate.
|
|
85
|
+
*
|
|
86
|
+
* @experimental This interceptor is experimental and APIs may change without notice.
|
|
87
|
+
*/
|
|
88
|
+
export class OpenTelemetryActivityOutboundInterceptor implements ActivityOutboundCallsInterceptor {
|
|
89
|
+
constructor(protected readonly ctx: ActivityContext) {}
|
|
90
|
+
|
|
91
|
+
public getLogAttributes(
|
|
92
|
+
input: GetLogAttributesInput,
|
|
93
|
+
next: Next<ActivityOutboundCallsInterceptor, 'getLogAttributes'>
|
|
94
|
+
): Record<string, unknown> {
|
|
95
|
+
const span = otel.trace.getSpan(otel.context.active());
|
|
96
|
+
const spanContext = span?.spanContext();
|
|
97
|
+
if (spanContext && otel.isSpanContextValid(spanContext)) {
|
|
98
|
+
return next({
|
|
99
|
+
trace_id: spanContext.traceId,
|
|
100
|
+
span_id: spanContext.spanId,
|
|
101
|
+
trace_flags: `0${spanContext.traceFlags.toString(16)}`,
|
|
102
|
+
...input,
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
return next(input);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public getMetricTags(
|
|
110
|
+
input: GetMetricTagsInput,
|
|
111
|
+
next: Next<ActivityOutboundCallsInterceptor, 'getMetricTags'>
|
|
112
|
+
): GetMetricTagsInput {
|
|
113
|
+
return next(input);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Intercepts inbound Nexus Operation calls on the worker.
|
|
119
|
+
*
|
|
120
|
+
* Wraps `startOperation` and `cancelOperation` in opentelemetry Spans, linking to a parent Span context
|
|
121
|
+
* if one is provided in the Nexus request headers.
|
|
122
|
+
*
|
|
123
|
+
* @experimental This interceptor is experimental and APIs may change without notice.
|
|
124
|
+
*/
|
|
125
|
+
export class OpenTelemetryNexusInboundInterceptor implements NexusInboundCallsInterceptor {
|
|
126
|
+
protected readonly tracer: otel.Tracer;
|
|
127
|
+
|
|
128
|
+
constructor(
|
|
129
|
+
protected readonly ctx: nexus.OperationContext,
|
|
130
|
+
options?: InterceptorOptions
|
|
131
|
+
) {
|
|
132
|
+
this.tracer = options?.tracer ?? otel.trace.getTracer('@temporalio/interceptor-nexus');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async startOperation(
|
|
136
|
+
input: NexusStartOperationInput,
|
|
137
|
+
next: Next<NexusInboundCallsInterceptor, 'startOperation'>
|
|
138
|
+
): Promise<NexusStartOperationOutput> {
|
|
139
|
+
const context = extractContextFromNexusHeaders(input.ctx.headers);
|
|
140
|
+
const spanName = `${SpanName.NEXUS_START_OPERATION_EXECUTE}${SPAN_DELIMITER}${input.ctx.service}/${input.ctx.operation}`;
|
|
141
|
+
return await instrument({
|
|
142
|
+
tracer: this.tracer,
|
|
143
|
+
spanName,
|
|
144
|
+
fn: (span) => {
|
|
145
|
+
span.setAttribute(NEXUS_SERVICE_ATTR_KEY, input.ctx.service);
|
|
146
|
+
span.setAttribute(NEXUS_OPERATION_ATTR_KEY, input.ctx.operation);
|
|
147
|
+
return next(input);
|
|
148
|
+
},
|
|
149
|
+
context,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async cancelOperation(
|
|
154
|
+
input: NexusCancelOperationInput,
|
|
155
|
+
next: Next<NexusInboundCallsInterceptor, 'cancelOperation'>
|
|
156
|
+
): Promise<void> {
|
|
157
|
+
const context = extractContextFromNexusHeaders(input.ctx.headers);
|
|
158
|
+
const spanName = `${SpanName.NEXUS_CANCEL_OPERATION_EXECUTE}${SPAN_DELIMITER}${input.ctx.service}/${input.ctx.operation}`;
|
|
159
|
+
return await instrument({
|
|
160
|
+
tracer: this.tracer,
|
|
161
|
+
spanName,
|
|
162
|
+
fn: (span) => {
|
|
163
|
+
span.setAttribute(NEXUS_SERVICE_ATTR_KEY, input.ctx.service);
|
|
164
|
+
span.setAttribute(NEXUS_OPERATION_ATTR_KEY, input.ctx.operation);
|
|
165
|
+
return next(input);
|
|
166
|
+
},
|
|
167
|
+
context,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Intercepts outbound calls from a Nexus Operation handler.
|
|
174
|
+
*
|
|
175
|
+
* Attaches OpenTelemetry context tracing attributes to emitted log messages.
|
|
176
|
+
*
|
|
177
|
+
* @experimental This interceptor is experimental and APIs may change without notice.
|
|
178
|
+
*/
|
|
179
|
+
export class OpenTelemetryNexusOutboundInterceptor implements NexusOutboundCallsInterceptor {
|
|
180
|
+
constructor(protected readonly ctx: nexus.OperationContext) {}
|
|
181
|
+
|
|
182
|
+
public getLogAttributes(
|
|
183
|
+
input: GetLogAttributesInput,
|
|
184
|
+
next: Next<NexusOutboundCallsInterceptor, 'getLogAttributes'>
|
|
185
|
+
): Record<string, unknown> {
|
|
186
|
+
const span = otel.trace.getSpan(otel.context.active());
|
|
187
|
+
const spanContext = span?.spanContext();
|
|
188
|
+
if (spanContext && otel.isSpanContextValid(spanContext)) {
|
|
189
|
+
return next({
|
|
190
|
+
trace_id: spanContext.traceId,
|
|
191
|
+
span_id: spanContext.spanId,
|
|
192
|
+
trace_flags: `0${spanContext.traceFlags.toString(16)}`,
|
|
193
|
+
...input,
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
return next(input);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public getMetricTags(
|
|
201
|
+
input: GetMetricTagsInput,
|
|
202
|
+
next: Next<NexusOutboundCallsInterceptor, 'getMetricTags'>
|
|
203
|
+
): GetMetricTagsInput {
|
|
204
|
+
return next(input);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Takes an opentelemetry SpanProcessor and turns it into an injected Workflow span exporter sink.
|
|
210
|
+
*/
|
|
211
|
+
export function makeWorkflowExporter(
|
|
212
|
+
processor: SpanProcessor,
|
|
213
|
+
resource: Resource
|
|
214
|
+
): InjectedSink<OpenTelemetryWorkflowExporter> {
|
|
215
|
+
return {
|
|
216
|
+
export: {
|
|
217
|
+
fn: (info, spanData) => {
|
|
218
|
+
const spans = spanData.map((serialized) => {
|
|
219
|
+
Object.assign(serialized.attributes, info);
|
|
220
|
+
// Spans are copied over from the isolate and are converted to ReadableSpan instances
|
|
221
|
+
return extractReadableSpan(serialized, resource);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
spans.forEach((span) => processor.onEnd(span));
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Deserialize a serialized span created by the Workflow isolate
|
|
232
|
+
*/
|
|
233
|
+
function extractReadableSpan(serializable: SerializableSpan, resource: Resource): ReadableSpan {
|
|
234
|
+
const {
|
|
235
|
+
spanContext: { traceState, ...restSpanContext },
|
|
236
|
+
parentSpanContext: serializedParentSpanContext,
|
|
237
|
+
instrumentationScope,
|
|
238
|
+
...rest
|
|
239
|
+
} = serializable;
|
|
240
|
+
const spanContext: otel.SpanContext = {
|
|
241
|
+
// Reconstruct the TraceState from the serialized string.
|
|
242
|
+
traceState: traceState ? createTraceState(traceState) : undefined,
|
|
243
|
+
...restSpanContext,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
let parentSpanContext: otel.SpanContext | undefined;
|
|
247
|
+
if (serializedParentSpanContext) {
|
|
248
|
+
const { traceState: parentTraceState, ...restParentSpanContext } = serializedParentSpanContext;
|
|
249
|
+
parentSpanContext = {
|
|
250
|
+
traceState: parentTraceState ? createTraceState(parentTraceState) : undefined,
|
|
251
|
+
...restParentSpanContext,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
spanContext() {
|
|
257
|
+
return spanContext;
|
|
258
|
+
},
|
|
259
|
+
parentSpanContext,
|
|
260
|
+
instrumentationScope,
|
|
261
|
+
resource,
|
|
262
|
+
...rest,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type AsyncLocalStorage } from 'async_hooks';
|
|
2
|
+
import * as otel from '@opentelemetry/api';
|
|
3
|
+
|
|
4
|
+
export class ContextManager implements otel.ContextManager {
|
|
5
|
+
// The workflow sandbox provides AsyncLocalStorage through globalThis.
|
|
6
|
+
protected storage: AsyncLocalStorage<otel.Context> = new (globalThis as any).AsyncLocalStorage();
|
|
7
|
+
|
|
8
|
+
active(): otel.Context {
|
|
9
|
+
return this.storage.getStore() || otel.ROOT_CONTEXT;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
bind<T>(context: otel.Context, target: T): T {
|
|
13
|
+
if (typeof target !== 'function') {
|
|
14
|
+
throw new TypeError(`Only function binding is supported, got ${typeof target}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Stolen from https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts
|
|
18
|
+
const contextWrapper = (...args: unknown[]) => {
|
|
19
|
+
return this.with(context, () => target.apply(this, args));
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(contextWrapper, 'length', {
|
|
22
|
+
enumerable: false,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: false,
|
|
25
|
+
value: target.length,
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* It isn't possible to tell Typescript that contextWrapper is the same as T
|
|
29
|
+
* so we forced to cast as any here.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
return contextWrapper as any;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
enable(): this {
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
disable(): this {
|
|
40
|
+
this.storage.disable();
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(
|
|
45
|
+
context: otel.Context,
|
|
46
|
+
fn: F,
|
|
47
|
+
thisArg?: ThisParameterType<F>,
|
|
48
|
+
...args: A
|
|
49
|
+
): ReturnType<F> {
|
|
50
|
+
const cb = thisArg == null ? fn : fn.bind(thisArg);
|
|
51
|
+
return this.storage.run(context, cb, ...args);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type * as otel from '@opentelemetry/api';
|
|
2
|
+
import type * as tracing from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
import type { InstrumentationScope } from '@opentelemetry/core';
|
|
4
|
+
import type { Sink, Sinks } from '@temporalio/workflow';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Serializable version of SpanContext where traceState is converted to a string.
|
|
8
|
+
*/
|
|
9
|
+
export type SerializableSpanContext = Omit<otel.SpanContext, 'traceState'> & { traceState?: string };
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Serializable version of the opentelemetry Span for cross isolate copying
|
|
13
|
+
*/
|
|
14
|
+
export interface SerializableSpan {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly kind: otel.SpanKind;
|
|
17
|
+
readonly spanContext: SerializableSpanContext;
|
|
18
|
+
readonly parentSpanContext?: SerializableSpanContext;
|
|
19
|
+
readonly startTime: otel.HrTime;
|
|
20
|
+
readonly endTime: otel.HrTime;
|
|
21
|
+
readonly status: otel.SpanStatus;
|
|
22
|
+
readonly attributes: otel.Attributes;
|
|
23
|
+
readonly links: otel.Link[];
|
|
24
|
+
readonly events: tracing.TimedEvent[];
|
|
25
|
+
readonly duration: otel.HrTime;
|
|
26
|
+
readonly ended: boolean;
|
|
27
|
+
readonly droppedAttributesCount: number;
|
|
28
|
+
readonly droppedLinksCount: number;
|
|
29
|
+
readonly droppedEventsCount: number;
|
|
30
|
+
// readonly resource: Resource;
|
|
31
|
+
readonly instrumentationScope: InstrumentationScope;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface OpenTelemetryWorkflowExporter extends Sink {
|
|
35
|
+
export(span: SerializableSpan[]): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Required external dependencies for Workflow interceptor to export spans
|
|
40
|
+
*/
|
|
41
|
+
export interface OpenTelemetrySinks extends Sinks {
|
|
42
|
+
exporter: OpenTelemetryWorkflowExporter;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export enum SpanName {
|
|
46
|
+
/**
|
|
47
|
+
* Workflow is scheduled by a client
|
|
48
|
+
*/
|
|
49
|
+
WORKFLOW_START = 'StartWorkflow',
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Workflow is signalled
|
|
53
|
+
*/
|
|
54
|
+
WORKFLOW_SIGNAL = 'SignalWorkflow',
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Workflow is client calls signalWithStart
|
|
58
|
+
*/
|
|
59
|
+
WORKFLOW_SIGNAL_WITH_START = 'SignalWithStartWorkflow',
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Workflow is queried
|
|
63
|
+
*/
|
|
64
|
+
WORKFLOW_QUERY = 'QueryWorkflow',
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Workflow update is started by client
|
|
68
|
+
*/
|
|
69
|
+
WORKFLOW_START_UPDATE = 'StartWorkflowUpdate',
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Workflow is started with an update
|
|
73
|
+
*/
|
|
74
|
+
WORKFLOW_UPDATE_WITH_START = 'UpdateWithStartWorkflow',
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Workflow handles an incoming signal
|
|
78
|
+
*/
|
|
79
|
+
WORKFLOW_HANDLE_SIGNAL = 'HandleSignal',
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Workflow handles an incoming query
|
|
83
|
+
*/
|
|
84
|
+
WORKFLOW_HANDLE_QUERY = 'HandleQuery',
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Workflow handles an incoming update
|
|
88
|
+
*/
|
|
89
|
+
WORKFLOW_HANDLE_UPDATE = 'HandleUpdate',
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Workflow validates an incoming update
|
|
93
|
+
*/
|
|
94
|
+
WORKFLOW_VALIDATE_UPDATE = 'ValidateUpdate',
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Workflow is terminated
|
|
98
|
+
*/
|
|
99
|
+
WORKFLOW_TERMINATE = 'TerminateWorkflow',
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Workflow is cancelled
|
|
103
|
+
*/
|
|
104
|
+
WORKFLOW_CANCEL = 'CancelWorkflow',
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Workflow is described
|
|
108
|
+
*/
|
|
109
|
+
WORKFLOW_DESCRIBE = 'DescribeWorkflow',
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Workflow run is executing
|
|
113
|
+
*/
|
|
114
|
+
WORKFLOW_EXECUTE = 'RunWorkflow',
|
|
115
|
+
/**
|
|
116
|
+
* Child Workflow is started (by parent Workflow)
|
|
117
|
+
*/
|
|
118
|
+
CHILD_WORKFLOW_START = 'StartChildWorkflow',
|
|
119
|
+
/**
|
|
120
|
+
* Activity is scheduled by a Workflow
|
|
121
|
+
*/
|
|
122
|
+
ACTIVITY_START = 'StartActivity',
|
|
123
|
+
/**
|
|
124
|
+
* Activity is executing
|
|
125
|
+
*/
|
|
126
|
+
ACTIVITY_EXECUTE = 'RunActivity',
|
|
127
|
+
/**
|
|
128
|
+
* Workflow is continuing as new
|
|
129
|
+
*/
|
|
130
|
+
CONTINUE_AS_NEW = 'ContinueAsNew',
|
|
131
|
+
/**
|
|
132
|
+
* Nexus operation is started
|
|
133
|
+
*/
|
|
134
|
+
NEXUS_OPERATION_START = 'StartNexusOperation',
|
|
135
|
+
/**
|
|
136
|
+
* Nexus operation is executing
|
|
137
|
+
*/
|
|
138
|
+
NEXUS_START_OPERATION_EXECUTE = 'RunStartNexusOperation',
|
|
139
|
+
/**
|
|
140
|
+
* Nexus operation cancel is executing
|
|
141
|
+
*/
|
|
142
|
+
NEXUS_CANCEL_OPERATION_EXECUTE = 'RunCancelNexusOperation',
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const SPAN_DELIMITER = ':';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { IdGenerator } from '@opentelemetry/sdk-trace-base';
|
|
2
|
+
import { getRandomStream } from './workflow-imports';
|
|
3
|
+
|
|
4
|
+
const OTEL_ID_RANDOM_STREAM = '@temporalio/interceptors-opentelemetry-v2/id-generator';
|
|
5
|
+
|
|
6
|
+
function randomHex(length: number): string {
|
|
7
|
+
const stream = getRandomStream(OTEL_ID_RANDOM_STREAM);
|
|
8
|
+
const chars: string[] = [];
|
|
9
|
+
for (let i = 0; i < length; i++) {
|
|
10
|
+
const nibble = (stream.random() * 16) >>> 0;
|
|
11
|
+
chars.push(nibble.toString(16));
|
|
12
|
+
}
|
|
13
|
+
return chars.join('');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generates span and trace IDs from a named workflow random stream.
|
|
18
|
+
*/
|
|
19
|
+
export class DeterministicIdGenerator implements IdGenerator {
|
|
20
|
+
generateTraceId(): string {
|
|
21
|
+
const id = randomHex(32);
|
|
22
|
+
// Ensure non-zero per W3C Trace Context spec
|
|
23
|
+
return id === '00000000000000000000000000000000' ? '00000000000000000000000000000001' : id;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
generateSpanId(): string {
|
|
27
|
+
const id = randomHex(16);
|
|
28
|
+
return id === '0000000000000000' ? '0000000000000001' : id;
|
|
29
|
+
}
|
|
30
|
+
}
|