@diia-inhouse/workflow 3.2.6 → 3.3.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/dist/interceptors/activityTraceLogAttributes.js +26 -0
- package/dist/interceptors/spanContext.js +19 -0
- package/dist/interceptors/traceLogAttributes.js +20 -10
- package/dist/services/worker/runtimeLogger.js +36 -0
- package/dist/services/worker.d.ts +3 -2
- package/dist/services/worker.js +22 -7
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { activeSpanContext, spanContextLogAttributes } from "./spanContext.js";
|
|
2
|
+
//#region src/interceptors/activityTraceLogAttributes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Injects trace and span ids into activity log attributes.
|
|
5
|
+
*
|
|
6
|
+
* The SDK logs the activity lifecycle after the OpenTelemetry span has ended, so the inbound hook
|
|
7
|
+
* remembers the span context while it is still active and `getLogAttributes` falls back to it.
|
|
8
|
+
* `Activity started` precedes the chain entirely and stays untraced.
|
|
9
|
+
*/
|
|
10
|
+
var ActivityTraceLogAttributesInterceptor = class {
|
|
11
|
+
capturedSpanContext;
|
|
12
|
+
async execute(input, next) {
|
|
13
|
+
this.capturedSpanContext = activeSpanContext() ?? this.capturedSpanContext;
|
|
14
|
+
return await next(input);
|
|
15
|
+
}
|
|
16
|
+
getLogAttributes(input, next) {
|
|
17
|
+
const spanContext = activeSpanContext() ?? this.capturedSpanContext;
|
|
18
|
+
if (!spanContext) return next(input);
|
|
19
|
+
return next({
|
|
20
|
+
...spanContextLogAttributes(spanContext),
|
|
21
|
+
...input
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { ActivityTraceLogAttributesInterceptor };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as otel from "@opentelemetry/api";
|
|
2
|
+
//#region src/interceptors/spanContext.ts
|
|
3
|
+
/** Span context of the active span, if any. */
|
|
4
|
+
function activeSpanContext() {
|
|
5
|
+
const spanContext = otel.trace.getSpan(otel.context.active())?.spanContext();
|
|
6
|
+
return spanContext && otel.isSpanContextValid(spanContext) ? spanContext : void 0;
|
|
7
|
+
}
|
|
8
|
+
/** Trace log attributes, in both the Temporal SDK and the diia naming. */
|
|
9
|
+
function spanContextLogAttributes(spanContext) {
|
|
10
|
+
return {
|
|
11
|
+
trace_id: spanContext.traceId,
|
|
12
|
+
span_id: spanContext.spanId,
|
|
13
|
+
trace_flags: `0${spanContext.traceFlags.toString(16)}`,
|
|
14
|
+
traceId: spanContext.traceId,
|
|
15
|
+
spanId: spanContext.spanId
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { activeSpanContext, spanContextLogAttributes };
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { activeSpanContext, spanContextLogAttributes } from "./spanContext.js";
|
|
2
2
|
//#region src/interceptors/traceLogAttributes.ts
|
|
3
|
-
/** Injects
|
|
3
|
+
/** Injects trace and span ids into workflow log attributes. */
|
|
4
4
|
var TraceLogAttributesInterceptor = class {
|
|
5
|
+
capturedSpanContext;
|
|
6
|
+
async execute(input, next) {
|
|
7
|
+
this.capturedSpanContext = activeSpanContext() ?? this.capturedSpanContext;
|
|
8
|
+
return await next(input);
|
|
9
|
+
}
|
|
5
10
|
getLogAttributes(input, next) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
return attrs;
|
|
11
|
+
const spanContext = activeSpanContext() ?? this.capturedSpanContext;
|
|
12
|
+
if (!spanContext) return next(input);
|
|
13
|
+
return next({
|
|
14
|
+
...spanContextLogAttributes(spanContext),
|
|
15
|
+
...input
|
|
16
|
+
});
|
|
13
17
|
}
|
|
14
18
|
};
|
|
15
|
-
const interceptors = () =>
|
|
19
|
+
const interceptors = () => {
|
|
20
|
+
const interceptor = new TraceLogAttributesInterceptor();
|
|
21
|
+
return {
|
|
22
|
+
inbound: [interceptor],
|
|
23
|
+
outbound: [interceptor]
|
|
24
|
+
};
|
|
25
|
+
};
|
|
16
26
|
//#endregion
|
|
17
27
|
export { interceptors };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/services/worker/runtimeLogger.ts
|
|
2
|
+
const ERROR_META_KEY = "error";
|
|
3
|
+
const NORMALIZED_ERROR_META_KEY = "err";
|
|
4
|
+
function normalizeMeta(meta) {
|
|
5
|
+
if (!meta || !(ERROR_META_KEY in meta) || NORMALIZED_ERROR_META_KEY in meta) return meta;
|
|
6
|
+
const { [ERROR_META_KEY]: error, ...rest } = meta;
|
|
7
|
+
return {
|
|
8
|
+
...rest,
|
|
9
|
+
[NORMALIZED_ERROR_META_KEY]: error
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Adapts a diia `Logger` to the Temporal runtime `Logger`.
|
|
14
|
+
*
|
|
15
|
+
* Remaps failures to the `err` key the diia logger serializes, and implements the
|
|
16
|
+
* level-first `log()` signature the two interfaces disagree on.
|
|
17
|
+
*/
|
|
18
|
+
function toTemporalRuntimeLogger(logger) {
|
|
19
|
+
const levels = {
|
|
20
|
+
TRACE: (message, meta) => logger.trace(message, meta),
|
|
21
|
+
DEBUG: (message, meta) => logger.debug(message, meta),
|
|
22
|
+
INFO: (message, meta) => logger.info(message, meta),
|
|
23
|
+
WARN: (message, meta) => logger.warn(message, meta),
|
|
24
|
+
ERROR: (message, meta) => logger.error(message, meta)
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
log: (level, message, meta) => levels[level]?.(message, normalizeMeta(meta)),
|
|
28
|
+
trace: (message, meta) => levels.TRACE(message, normalizeMeta(meta)),
|
|
29
|
+
debug: (message, meta) => levels.DEBUG(message, normalizeMeta(meta)),
|
|
30
|
+
info: (message, meta) => levels.INFO(message, normalizeMeta(meta)),
|
|
31
|
+
warn: (message, meta) => levels.WARN(message, normalizeMeta(meta)),
|
|
32
|
+
error: (message, meta) => levels.ERROR(message, normalizeMeta(meta))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { toTemporalRuntimeLogger };
|
|
@@ -4,7 +4,7 @@ import { WorkerHealthDetails, WorkerHealthService } from "./workerHealth.js";
|
|
|
4
4
|
import { buildWorkerIdentity } from "./worker/identity.js";
|
|
5
5
|
import { EnvService } from "@diia-inhouse/env";
|
|
6
6
|
import { AlsData, Logger } from "@diia-inhouse/types";
|
|
7
|
-
import { Worker, WorkerOptions } from "@temporalio/worker";
|
|
7
|
+
import { Worker, WorkerInterceptors, WorkerOptions } from "@temporalio/worker";
|
|
8
8
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
9
|
|
|
10
10
|
//#region src/services/worker.d.ts
|
|
@@ -31,6 +31,7 @@ declare function applyWorkerProcessConfig(config: AppConfig): void;
|
|
|
31
31
|
* and returns a filesystem path suitable for Temporal's worker.
|
|
32
32
|
*/
|
|
33
33
|
declare function toWorkflowsPath(input: string): string;
|
|
34
|
+
declare function buildWorkerInterceptors(tracingEnabled: boolean, asyncLocalStorage: AsyncLocalStorage<AlsData> | undefined, logger: Logger | undefined, workflowsPath: string | undefined): WorkerInterceptors | undefined;
|
|
34
35
|
declare function instantiateActivities(app: App, workerActivities: Record<string, ActivityClass>): Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
35
36
|
/**
|
|
36
37
|
* Runs the Temporal worker in the **dedicated worker process**.
|
|
@@ -131,4 +132,4 @@ declare function initWorker({
|
|
|
131
132
|
service?: string;
|
|
132
133
|
}, envService: EnvService, logger?: Logger, nodeTracerProvider?: NodeTracerProviderLike, asyncLocalStorage?: AsyncLocalStorage<AlsData>): Promise<Worker>;
|
|
133
134
|
//#endregion
|
|
134
|
-
export { type ActivityClass, type App, type RunInProcessWorkerOptions, type RunStandaloneWorkerOptions, type WorkerBootstrapOptions, type WorkerHealthDetails, WorkerHealthService, type WorkerRunOptions, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath };
|
|
135
|
+
export { type ActivityClass, type App, type RunInProcessWorkerOptions, type RunStandaloneWorkerOptions, type WorkerBootstrapOptions, type WorkerHealthDetails, WorkerHealthService, type WorkerRunOptions, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, buildWorkerInterceptors, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath };
|
package/dist/services/worker.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getDataConverter } from "../encryption/dataConverter.js";
|
|
2
2
|
import "../encryption/index.js";
|
|
3
3
|
import { traceExporter } from "../instrumentation.js";
|
|
4
|
+
import { ActivityTraceLogAttributesInterceptor } from "../interceptors/activityTraceLogAttributes.js";
|
|
4
5
|
import { AsyncLocalStorageBridgeInterceptor } from "../interceptors/asyncLocalStorageBridge.js";
|
|
5
6
|
import { buildWorkerIdentity } from "./worker/identity.js";
|
|
6
7
|
import { deriveWorkflowTypes, registerWorkerInfo } from "./worker/info.js";
|
|
8
|
+
import { toTemporalRuntimeLogger } from "./worker/runtimeLogger.js";
|
|
7
9
|
import { WorkerHealthService } from "./workerHealth.js";
|
|
8
10
|
import { EnvService } from "@diia-inhouse/env";
|
|
9
11
|
import { NativeConnection, Runtime, Worker } from "@temporalio/worker";
|
|
@@ -58,17 +60,30 @@ function toWorkflowsPath(input) {
|
|
|
58
60
|
/**
|
|
59
61
|
* Builds worker interceptors with OpenTelemetry and AsyncLocalStorage support.
|
|
60
62
|
* OpenTelemetry creates span first, then AsyncLocalStorage bridge extracts traceId.
|
|
63
|
+
*
|
|
64
|
+
* Order matters: the first factory is the outermost, so the ones after it see an open span.
|
|
61
65
|
*/
|
|
62
66
|
const traceLogAttributesModulePath = path.resolve(import.meta.dirname, "../interceptors/traceLogAttributes");
|
|
67
|
+
function traceLogAttributesInterceptor() {
|
|
68
|
+
const interceptor = new ActivityTraceLogAttributesInterceptor();
|
|
69
|
+
return {
|
|
70
|
+
inbound: interceptor,
|
|
71
|
+
outbound: interceptor
|
|
72
|
+
};
|
|
73
|
+
}
|
|
63
74
|
function buildWorkerInterceptors(tracingEnabled, asyncLocalStorage, logger, workflowsPath) {
|
|
64
75
|
if (tracingEnabled) {
|
|
65
76
|
const workflowModules = [traceLogAttributesModulePath];
|
|
66
77
|
if (workflowsPath) workflowModules.unshift(workflowsPath);
|
|
67
78
|
return {
|
|
68
|
-
activity: [
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
activity: [
|
|
80
|
+
(ctx) => ({
|
|
81
|
+
inbound: new OpenTelemetryActivityInboundInterceptor(ctx),
|
|
82
|
+
outbound: new OpenTelemetryActivityOutboundInterceptor(ctx)
|
|
83
|
+
}),
|
|
84
|
+
traceLogAttributesInterceptor,
|
|
85
|
+
...asyncLocalStorage && logger ? [(ctx) => ({ inbound: new AsyncLocalStorageBridgeInterceptor(ctx, asyncLocalStorage, logger) })] : []
|
|
86
|
+
],
|
|
72
87
|
workflowModules
|
|
73
88
|
};
|
|
74
89
|
}
|
|
@@ -76,7 +91,7 @@ function buildWorkerInterceptors(tracingEnabled, asyncLocalStorage, logger, work
|
|
|
76
91
|
activity: [(ctx) => ({
|
|
77
92
|
inbound: new AsyncLocalStorageBridgeInterceptor(ctx, asyncLocalStorage, logger),
|
|
78
93
|
outbound: new OpenTelemetryActivityOutboundInterceptor(ctx)
|
|
79
|
-
})],
|
|
94
|
+
}), traceLogAttributesInterceptor],
|
|
80
95
|
workflowModules: workflowsPath ? [workflowsPath] : []
|
|
81
96
|
};
|
|
82
97
|
}
|
|
@@ -277,7 +292,7 @@ function tryResolve(container, key) {
|
|
|
277
292
|
async function initWorker({ temporal: temporalConfig, metrics: { custom: metricsConfig } }, options, envService, logger, nodeTracerProvider, asyncLocalStorage) {
|
|
278
293
|
const { encryptionEnabled, encryptionKeyId, encryptionKeyRefreshInterval, namespace = "default", address, taskQueue } = temporalConfig;
|
|
279
294
|
const runtimeParams = {};
|
|
280
|
-
if (logger) runtimeParams.logger = logger.child({ taskQueue });
|
|
295
|
+
if (logger) runtimeParams.logger = toTemporalRuntimeLogger(logger.child({ taskQueue }));
|
|
281
296
|
const temporalMetrics = metricsConfig.scrapers?.find((s) => s.name === "temporal");
|
|
282
297
|
if (temporalMetrics && !temporalMetrics.disabled) runtimeParams.telemetryOptions = { metrics: { prometheus: {
|
|
283
298
|
bindAddress: `0.0.0.0:${temporalMetrics.port}`,
|
|
@@ -321,4 +336,4 @@ async function initWorker({ temporal: temporalConfig, metrics: { custom: metrics
|
|
|
321
336
|
}
|
|
322
337
|
}
|
|
323
338
|
//#endregion
|
|
324
|
-
export { WorkerHealthService, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath };
|
|
339
|
+
export { WorkerHealthService, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, buildWorkerInterceptors, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath };
|
package/dist/worker.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { workflowInterceptors } from "./interceptors.js";
|
|
|
2
2
|
import { ActivityClass, App, RunInProcessWorkerOptions, RunStandaloneWorkerOptions, WorkerBootstrapOptions, WorkerRunOptions } from "./interfaces/services/worker.js";
|
|
3
3
|
import { WorkerHealthDetails, WorkerHealthService } from "./services/workerHealth.js";
|
|
4
4
|
import { buildWorkerIdentity } from "./services/worker/identity.js";
|
|
5
|
-
import { applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath } from "./services/worker.js";
|
|
5
|
+
import { applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerInterceptors, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath } from "./services/worker.js";
|
|
6
6
|
import { RegisterWorkerInfoParams, WORKER_INFO_METRIC, WorkerInfoLabels, deriveWorkflowTypes, registerWorkerInfo, taskQueueToService } from "./services/worker/info.js";
|
|
7
7
|
import { NativeConnection, NativeConnectionPlugin, Runtime, State, Worker, WorkerDeploymentOptions, WorkerInterceptors, WorkerOptions, WorkerPlugin, WorkerStatus, bundleWorkflowCode } from "@temporalio/worker";
|
|
8
|
-
export { type ActivityClass, type App, NativeConnection, type NativeConnectionPlugin, RegisterWorkerInfoParams, type RunInProcessWorkerOptions, type RunStandaloneWorkerOptions, Runtime, type State, WORKER_INFO_METRIC, Worker, type WorkerBootstrapOptions, type WorkerDeploymentOptions, type WorkerHealthDetails, WorkerHealthService, WorkerInfoLabels, type WorkerInterceptors, type WorkerOptions, type WorkerPlugin, type WorkerRunOptions, type WorkerStatus, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, bundleWorkflowCode, deriveWorkflowTypes, initWorker, instantiateActivities, registerWorkerInfo, runInProcessWorker, runStandaloneWorker, taskQueueToService, toWorkflowsPath, workflowInterceptors };
|
|
8
|
+
export { type ActivityClass, type App, NativeConnection, type NativeConnectionPlugin, RegisterWorkerInfoParams, type RunInProcessWorkerOptions, type RunStandaloneWorkerOptions, Runtime, type State, WORKER_INFO_METRIC, Worker, type WorkerBootstrapOptions, type WorkerDeploymentOptions, type WorkerHealthDetails, WorkerHealthService, WorkerInfoLabels, type WorkerInterceptors, type WorkerOptions, type WorkerPlugin, type WorkerRunOptions, type WorkerStatus, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, buildWorkerInterceptors, bundleWorkflowCode, deriveWorkflowTypes, initWorker, instantiateActivities, registerWorkerInfo, runInProcessWorker, runStandaloneWorker, taskQueueToService, toWorkflowsPath, workflowInterceptors };
|
package/dist/worker.js
CHANGED
|
@@ -2,6 +2,6 @@ import { workflowInterceptors } from "./interceptors.js";
|
|
|
2
2
|
import { buildWorkerIdentity } from "./services/worker/identity.js";
|
|
3
3
|
import { WORKER_INFO_METRIC, deriveWorkflowTypes, registerWorkerInfo, taskQueueToService } from "./services/worker/info.js";
|
|
4
4
|
import { WorkerHealthService } from "./services/workerHealth.js";
|
|
5
|
-
import { applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath } from "./services/worker.js";
|
|
5
|
+
import { applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerInterceptors, initWorker, instantiateActivities, runInProcessWorker, runStandaloneWorker, toWorkflowsPath } from "./services/worker.js";
|
|
6
6
|
import { NativeConnection, Runtime, Worker, bundleWorkflowCode } from "@temporalio/worker";
|
|
7
|
-
export { NativeConnection, Runtime, WORKER_INFO_METRIC, Worker, WorkerHealthService, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, bundleWorkflowCode, deriveWorkflowTypes, initWorker, instantiateActivities, registerWorkerInfo, runInProcessWorker, runStandaloneWorker, taskQueueToService, toWorkflowsPath, workflowInterceptors };
|
|
7
|
+
export { NativeConnection, Runtime, WORKER_INFO_METRIC, Worker, WorkerHealthService, applyServiceProcessConfig, applyWorkerProcessConfig, bootstrapWorker, buildWorkerIdentity, buildWorkerInterceptors, bundleWorkflowCode, deriveWorkflowTypes, initWorker, instantiateActivities, registerWorkerInfo, runInProcessWorker, runStandaloneWorker, taskQueueToService, toWorkflowsPath, workflowInterceptors };
|