@temporalio/interceptors-opentelemetry 1.0.0-rc.0 → 1.0.1
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.md +1 -1
- package/README.md +2 -2
- package/lib/client/index.js +1 -1
- package/lib/client/index.js.map +1 -1
- package/lib/index.d.ts +12 -0
- package/lib/index.js +31 -0
- package/lib/index.js.map +1 -0
- package/lib/worker/index.js +1 -1
- package/lib/worker/index.js.map +1 -1
- package/lib/workflow/definitions.d.ts +1 -1
- package/lib/workflow/definitions.js.map +1 -1
- package/lib/workflow/index.js +1 -1
- package/lib/workflow/index.js.map +1 -1
- package/package.json +15 -14
- package/src/client/index.ts +35 -0
- package/src/index.ts +13 -0
- package/src/instrumentation.ts +52 -0
- package/src/worker/index.ts +68 -0
- package/src/workflow/context-manager.ts +52 -0
- package/src/workflow/definitions.ts +71 -0
- package/src/workflow/index.ts +133 -0
- package/src/workflow/runtime.ts +18 -0
- package/src/workflow/span-exporter.ts +35 -0
package/LICENSE.md
CHANGED
|
@@ -2,7 +2,7 @@ Temporal TypeScript SDK
|
|
|
2
2
|
|
|
3
3
|
MIT License
|
|
4
4
|
|
|
5
|
-
Copyright (c) 2021 Temporal Technologies
|
|
5
|
+
Copyright (c) 2021 Temporal Technologies Inc. All Rights Reserved
|
|
6
6
|
|
|
7
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@temporalio/interceptors-opentelemetry)
|
|
4
4
|
|
|
5
|
-
[Temporal](https://temporal.io)'s [TypeScript SDK](https://docs.temporal.io/typescript/introduction) interceptors
|
|
5
|
+
[Temporal](https://temporal.io)'s [TypeScript SDK](https://docs.temporal.io/typescript/introduction) interceptors for tracing Workflow and Activity executions with [OpenTelemetry](https://opentelemetry.io/).
|
|
6
6
|
|
|
7
7
|
- [Interceptors docs](https://docs.temporal.io/typescript/interceptors)
|
|
8
|
-
- [OpenTelemetry
|
|
8
|
+
- [OpenTelemetry interceptors docs](https://docs.temporal.io/typescript/logging/#opentelemetry-tracing)
|
package/lib/client/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.OpenTelemetryWorkflowClientCallsInterceptor = void 0;
|
|
27
27
|
const otel = __importStar(require("@opentelemetry/api"));
|
|
28
|
-
const otel_1 = require("@temporalio/
|
|
28
|
+
const otel_1 = require("@temporalio/common/lib/otel");
|
|
29
29
|
const instrumentation_1 = require("../instrumentation");
|
|
30
30
|
const workflow_1 = require("../workflow");
|
|
31
31
|
/**
|
package/lib/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yDAA2C;AAE3C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yDAA2C;AAE3C,sDAAkF;AAClF,wDAAgD;AAChD,0CAAuD;AAMvD;;;;GAIG;AACH,MAAa,2CAA2C;IAGtD,YAAY,OAA4B;QACtC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAyB,EAAE,IAAmD;QACxF,OAAO,MAAM,IAAA,4BAAU,EAAC;YACtB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,GAAG,mBAAQ,CAAC,cAAc,GAAG,yBAAc,GAAG,KAAK,CAAC,YAAY,EAAE;YAC5E,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACjB,MAAM,OAAO,GAAG,MAAM,IAAA,yBAAkB,EAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBAChD,IAAI,CAAC,YAAY,CAAC,sBAAe,EAAE,KAAK,CAAC,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACf,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAnBD,kGAmBC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `npm i @temporalio/interceptors-opentelemetry`
|
|
3
|
+
*
|
|
4
|
+
* Interceptors that add OpenTelemetry tracing.
|
|
5
|
+
*
|
|
6
|
+
* [Documentation](https://docs.temporal.io/typescript/logging#opentelemetry-tracing)
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
export * from './workflow';
|
|
11
|
+
export * from './worker';
|
|
12
|
+
export { OpenTelemetryWorkflowClientCallsInterceptor } from './client';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `npm i @temporalio/interceptors-opentelemetry`
|
|
4
|
+
*
|
|
5
|
+
* Interceptors that add OpenTelemetry tracing.
|
|
6
|
+
*
|
|
7
|
+
* [Documentation](https://docs.temporal.io/typescript/logging#opentelemetry-tracing)
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
23
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.OpenTelemetryWorkflowClientCallsInterceptor = void 0;
|
|
27
|
+
__exportStar(require("./workflow"), exports);
|
|
28
|
+
__exportStar(require("./worker"), exports);
|
|
29
|
+
var client_1 = require("./client");
|
|
30
|
+
Object.defineProperty(exports, "OpenTelemetryWorkflowClientCallsInterceptor", { enumerable: true, get: function () { return client_1.OpenTelemetryWorkflowClientCallsInterceptor; } });
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,2CAAyB;AACzB,mCAAuE;AAA9D,qIAAA,2CAA2C,OAAA"}
|
package/lib/worker/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.makeWorkflowExporter = exports.OpenTelemetryActivityInboundInterceptor = void 0;
|
|
27
27
|
const otel = __importStar(require("@opentelemetry/api"));
|
|
28
|
-
const otel_1 = require("@temporalio/
|
|
28
|
+
const otel_1 = require("@temporalio/common/lib/otel");
|
|
29
29
|
const instrumentation_1 = require("../instrumentation");
|
|
30
30
|
const workflow_1 = require("../workflow");
|
|
31
31
|
/**
|
package/lib/worker/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yDAA2C;AAI3C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yDAA2C;AAI3C,sDAAwE;AAExE,wDAAgD;AAChD,0CAAwG;AAMxG;;;;;GAKG;AACH,MAAa,uCAAuC;IAGlD,YAA+B,GAAoB,EAAE,OAA4B;QAAlD,QAAG,GAAH,GAAG,CAAiB;QACjD,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC5F,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAA2B,EAAE,IAAsD;QAC/F,MAAM,OAAO,GAAG,MAAM,IAAA,gCAAyB,EAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,GAAG,mBAAQ,CAAC,gBAAgB,GAAG,yBAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QAC9F,OAAO,MAAM,IAAA,4BAAU,EAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7F,CAAC;CACF;AAZD,0FAYC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAClC,QAAsB,EACtB,QAAkB;IAElB,OAAO;QACL,MAAM,EAAE;YACN,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;gBACrB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;oBACxC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;oBAC3C,qFAAqF;oBACrF,OAAO,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACnD,CAAC,CAAC,CAAC;gBACH,0CAA0C;gBAC1C,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC1C,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAjBD,oDAiBC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,YAA8B,EAAE,QAAkB;IAC7E,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,YAAY,CAAC;IAC9C,OAAO;QACL,WAAW;YACT,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,QAAQ;QACR,GAAG,IAAI;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -13,7 +13,7 @@ export interface SerializableSpan {
|
|
|
13
13
|
readonly startTime: otel.HrTime;
|
|
14
14
|
readonly endTime: otel.HrTime;
|
|
15
15
|
readonly status: otel.SpanStatus;
|
|
16
|
-
readonly attributes: otel.
|
|
16
|
+
readonly attributes: otel.Attributes;
|
|
17
17
|
readonly links: otel.Link[];
|
|
18
18
|
readonly events: tracing.TimedEvent[];
|
|
19
19
|
readonly duration: otel.HrTime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/workflow/definitions.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/workflow/definitions.ts"],"names":[],"mappings":";;;AAqCA,IAAY,QA+BX;AA/BD,WAAY,QAAQ;IAClB;;OAEG;IACH,4CAAgC,CAAA;IAEhC;;OAEG;IACH,kEAAsD,CAAA;IAEtD;;OAEG;IACH,4CAAgC,CAAA;IAChC;;OAEG;IACH,uDAA2C,CAAA;IAC3C;;OAEG;IACH,4CAAgC,CAAA;IAChC;;OAEG;IACH,4CAAgC,CAAA;IAChC;;OAEG;IACH,6CAAiC,CAAA;AACnC,CAAC,EA/BW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QA+BnB;AAEY,QAAA,cAAc,GAAG,GAAG,CAAC"}
|
package/lib/workflow/index.js
CHANGED
|
@@ -29,7 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.OpenTelemetryInternalsInterceptor = exports.OpenTelemetryOutboundInterceptor = exports.OpenTelemetryInboundInterceptor = void 0;
|
|
30
30
|
require("./runtime"); // Patch the Workflow isolate runtime for opentelemetry
|
|
31
31
|
const tracing = __importStar(require("@opentelemetry/sdk-trace-base"));
|
|
32
|
-
const otel_1 = require("@temporalio/
|
|
32
|
+
const otel_1 = require("@temporalio/common/lib/otel");
|
|
33
33
|
const workflow_1 = require("@temporalio/workflow");
|
|
34
34
|
const instrumentation_1 = require("../instrumentation");
|
|
35
35
|
const context_manager_1 = require("./context-manager");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qBAAmB,CAAC,uDAAuD;AAE3E,uEAAyD;AACzD,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/interceptors-opentelemetry",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Temporal.io SDK interceptors bundle for tracing with opentelemetry",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -11,27 +11,28 @@
|
|
|
11
11
|
"interceptors",
|
|
12
12
|
"opentelemetry"
|
|
13
13
|
],
|
|
14
|
-
"author": "
|
|
14
|
+
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@opentelemetry/api": "^1.0
|
|
18
|
-
"@opentelemetry/core": "^1.
|
|
19
|
-
"@opentelemetry/resources": "^1.
|
|
20
|
-
"@opentelemetry/sdk-trace-base": "^1.
|
|
21
|
-
"@temporalio/client": "^1.0.
|
|
22
|
-
"@temporalio/common": "^1.0.
|
|
23
|
-
"@temporalio/worker": "^1.0.
|
|
24
|
-
"@temporalio/workflow": "^1.0.
|
|
17
|
+
"@opentelemetry/api": "^1.1.0",
|
|
18
|
+
"@opentelemetry/core": "^1.3.1",
|
|
19
|
+
"@opentelemetry/resources": "^1.3.1",
|
|
20
|
+
"@opentelemetry/sdk-trace-base": "^1.3.1",
|
|
21
|
+
"@temporalio/client": "^1.0.1",
|
|
22
|
+
"@temporalio/common": "^1.0.1",
|
|
23
|
+
"@temporalio/worker": "^1.0.1",
|
|
24
|
+
"@temporalio/workflow": "^1.0.1"
|
|
25
25
|
},
|
|
26
26
|
"bugs": {
|
|
27
27
|
"url": "https://github.com/temporalio/sdk-typescript/issues"
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/temporalio/sdk-typescript/tree/main/packages/interceptors-opentelemetry",
|
|
30
|
-
"files": [
|
|
31
|
-
"lib"
|
|
32
|
-
],
|
|
33
30
|
"publishConfig": {
|
|
34
31
|
"access": "public"
|
|
35
32
|
},
|
|
36
|
-
"
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"lib"
|
|
36
|
+
],
|
|
37
|
+
"gitHead": "a1dae539e72b6b088b400998d7bef482e8ed52f1"
|
|
37
38
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import { Next, WorkflowClientCallsInterceptor, WorkflowStartInput } from '@temporalio/client';
|
|
3
|
+
import { headersWithContext, RUN_ID_ATTR_KEY } from '@temporalio/common/lib/otel';
|
|
4
|
+
import { instrument } from '../instrumentation';
|
|
5
|
+
import { SpanName, SPAN_DELIMITER } from '../workflow';
|
|
6
|
+
|
|
7
|
+
export interface InterceptorOptions {
|
|
8
|
+
readonly tracer?: otel.Tracer;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Intercepts calls to start a Workflow.
|
|
13
|
+
*
|
|
14
|
+
* Wraps the operation in an opentelemetry Span and passes it to the Workflow via headers.
|
|
15
|
+
*/
|
|
16
|
+
export class OpenTelemetryWorkflowClientCallsInterceptor implements WorkflowClientCallsInterceptor {
|
|
17
|
+
protected readonly tracer: otel.Tracer;
|
|
18
|
+
|
|
19
|
+
constructor(options?: InterceptorOptions) {
|
|
20
|
+
this.tracer = options?.tracer ?? otel.trace.getTracer('@temporalio/interceptor-client');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async start(input: WorkflowStartInput, next: Next<WorkflowClientCallsInterceptor, 'start'>): Promise<string> {
|
|
24
|
+
return await instrument({
|
|
25
|
+
tracer: this.tracer,
|
|
26
|
+
spanName: `${SpanName.WORKFLOW_START}${SPAN_DELIMITER}${input.workflowType}`,
|
|
27
|
+
fn: async (span) => {
|
|
28
|
+
const headers = await headersWithContext(input.headers);
|
|
29
|
+
const runId = await next({ ...input, headers });
|
|
30
|
+
span.setAttribute(RUN_ID_ATTR_KEY, runId);
|
|
31
|
+
return runId;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `npm i @temporalio/interceptors-opentelemetry`
|
|
3
|
+
*
|
|
4
|
+
* Interceptors that add OpenTelemetry tracing.
|
|
5
|
+
*
|
|
6
|
+
* [Documentation](https://docs.temporal.io/typescript/logging#opentelemetry-tracing)
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export * from './workflow';
|
|
12
|
+
export * from './worker';
|
|
13
|
+
export { OpenTelemetryWorkflowClientCallsInterceptor } from './client';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* opentelemetry instrumentation helper functions
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import * as otel from '@opentelemetry/api';
|
|
6
|
+
|
|
7
|
+
async function wrapWithSpan<T>(
|
|
8
|
+
span: otel.Span,
|
|
9
|
+
fn: (span: otel.Span) => Promise<T>,
|
|
10
|
+
acceptableErrors?: (err: unknown) => boolean
|
|
11
|
+
): Promise<T> {
|
|
12
|
+
try {
|
|
13
|
+
const ret = await fn(span);
|
|
14
|
+
span.setStatus({ code: otel.SpanStatusCode.OK });
|
|
15
|
+
return ret;
|
|
16
|
+
} catch (err: any) {
|
|
17
|
+
if (acceptableErrors === undefined || !acceptableErrors(err)) {
|
|
18
|
+
span.setStatus({ code: otel.SpanStatusCode.ERROR });
|
|
19
|
+
span.recordException(err);
|
|
20
|
+
} else {
|
|
21
|
+
span.setStatus({ code: otel.SpanStatusCode.OK });
|
|
22
|
+
}
|
|
23
|
+
throw err;
|
|
24
|
+
} finally {
|
|
25
|
+
span.end();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface InstrumentOptions<T> {
|
|
30
|
+
tracer: otel.Tracer;
|
|
31
|
+
spanName: string;
|
|
32
|
+
fn: (span: otel.Span) => Promise<T>;
|
|
33
|
+
context?: otel.Context;
|
|
34
|
+
acceptableErrors?: (err: unknown) => boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Wraps `fn` in a span which ends when function returns or throws
|
|
38
|
+
*/
|
|
39
|
+
export async function instrument<T>({
|
|
40
|
+
tracer,
|
|
41
|
+
spanName,
|
|
42
|
+
fn,
|
|
43
|
+
context,
|
|
44
|
+
acceptableErrors,
|
|
45
|
+
}: InstrumentOptions<T>): Promise<T> {
|
|
46
|
+
if (context) {
|
|
47
|
+
return await otel.context.with(context, async () => {
|
|
48
|
+
return await tracer.startActiveSpan(spanName, async (span) => await wrapWithSpan(span, fn, acceptableErrors));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return await tracer.startActiveSpan(spanName, async (span) => await wrapWithSpan(span, fn, acceptableErrors));
|
|
52
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import { Resource } from '@opentelemetry/resources';
|
|
3
|
+
import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
4
|
+
import { Context as ActivityContext } from '@temporalio/activity';
|
|
5
|
+
import { extractContextFromHeaders } from '@temporalio/common/lib/otel';
|
|
6
|
+
import { ActivityExecuteInput, ActivityInboundCallsInterceptor, InjectedSink, Next } from '@temporalio/worker';
|
|
7
|
+
import { instrument } from '../instrumentation';
|
|
8
|
+
import { OpenTelemetryWorkflowExporter, SerializableSpan, SpanName, SPAN_DELIMITER } from '../workflow';
|
|
9
|
+
|
|
10
|
+
export interface InterceptorOptions {
|
|
11
|
+
readonly tracer?: otel.Tracer;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Intercepts calls to start an Activity.
|
|
16
|
+
*
|
|
17
|
+
* Wraps the operation in an opentelemetry Span and links it to a parent Span context if one is
|
|
18
|
+
* provided in the Activity input headers.
|
|
19
|
+
*/
|
|
20
|
+
export class OpenTelemetryActivityInboundInterceptor implements ActivityInboundCallsInterceptor {
|
|
21
|
+
protected readonly tracer: otel.Tracer;
|
|
22
|
+
|
|
23
|
+
constructor(protected readonly ctx: ActivityContext, options?: InterceptorOptions) {
|
|
24
|
+
this.tracer = options?.tracer ?? otel.trace.getTracer('@temporalio/interceptor-activity');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async execute(input: ActivityExecuteInput, next: Next<ActivityInboundCallsInterceptor, 'execute'>): Promise<unknown> {
|
|
28
|
+
const context = await extractContextFromHeaders(input.headers);
|
|
29
|
+
const spanName = `${SpanName.ACTIVITY_EXECUTE}${SPAN_DELIMITER}${this.ctx.info.activityType}`;
|
|
30
|
+
return await instrument({ tracer: this.tracer, spanName, fn: () => next(input), context });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Takes an opentelemetry SpanExporter and turns it into an injected Workflow span exporter sink
|
|
36
|
+
*/
|
|
37
|
+
export function makeWorkflowExporter(
|
|
38
|
+
exporter: SpanExporter,
|
|
39
|
+
resource: Resource
|
|
40
|
+
): InjectedSink<OpenTelemetryWorkflowExporter> {
|
|
41
|
+
return {
|
|
42
|
+
export: {
|
|
43
|
+
fn: (info, spanData) => {
|
|
44
|
+
const spans = spanData.map((serialized) => {
|
|
45
|
+
Object.assign(serialized.attributes, info);
|
|
46
|
+
// Spans are copied over from the isolate and are converted to ReadableSpan instances
|
|
47
|
+
return extractReadableSpan(serialized, resource);
|
|
48
|
+
});
|
|
49
|
+
// Ignore the export result for simplicity
|
|
50
|
+
exporter.export(spans, () => undefined);
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Deserialize a serialized span created by the Workflow isolate
|
|
58
|
+
*/
|
|
59
|
+
function extractReadableSpan(serializable: SerializableSpan, resource: Resource): ReadableSpan {
|
|
60
|
+
const { spanContext, ...rest } = serializable;
|
|
61
|
+
return {
|
|
62
|
+
spanContext() {
|
|
63
|
+
return spanContext;
|
|
64
|
+
},
|
|
65
|
+
resource,
|
|
66
|
+
...rest,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import { AsyncLocalStorage } from '@temporalio/workflow';
|
|
3
|
+
|
|
4
|
+
export class ContextManager implements otel.ContextManager {
|
|
5
|
+
protected storage = new AsyncLocalStorage<otel.Context>();
|
|
6
|
+
|
|
7
|
+
active(): otel.Context {
|
|
8
|
+
return this.storage.getStore() || otel.ROOT_CONTEXT;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
bind<T>(context: otel.Context, target: T): T {
|
|
12
|
+
if (typeof target !== 'function') {
|
|
13
|
+
throw new TypeError(`Only function binding is supported, got ${typeof target}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Stolen from https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts
|
|
17
|
+
const contextWrapper = (...args: unknown[]) => {
|
|
18
|
+
return this.with(context, () => target.apply(this, args));
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(contextWrapper, 'length', {
|
|
21
|
+
enumerable: false,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: false,
|
|
24
|
+
value: target.length,
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* It isn't possible to tell Typescript that contextWrapper is the same as T
|
|
28
|
+
* so we forced to cast as any here.
|
|
29
|
+
*/
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
return contextWrapper as any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
enable(): this {
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
disable(): this {
|
|
39
|
+
this.storage.disable();
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(
|
|
44
|
+
context: otel.Context,
|
|
45
|
+
fn: F,
|
|
46
|
+
thisArg?: ThisParameterType<F>,
|
|
47
|
+
...args: A
|
|
48
|
+
): ReturnType<F> {
|
|
49
|
+
const cb = thisArg == null ? fn : fn.bind(thisArg);
|
|
50
|
+
return this.storage.run(context, cb, ...args);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api';
|
|
2
|
+
import * as tracing from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
import { InstrumentationLibrary } from '@opentelemetry/core'; // eslint-disable deprecation/deprecation
|
|
4
|
+
import { Sink, Sinks } from '@temporalio/workflow';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Serializable version of the opentelemetry Span for cross isolate copying
|
|
8
|
+
*/
|
|
9
|
+
export interface SerializableSpan {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly kind: otel.SpanKind;
|
|
12
|
+
readonly spanContext: otel.SpanContext;
|
|
13
|
+
readonly parentSpanId?: string;
|
|
14
|
+
readonly startTime: otel.HrTime;
|
|
15
|
+
readonly endTime: otel.HrTime;
|
|
16
|
+
readonly status: otel.SpanStatus;
|
|
17
|
+
readonly attributes: otel.Attributes;
|
|
18
|
+
readonly links: otel.Link[];
|
|
19
|
+
readonly events: tracing.TimedEvent[];
|
|
20
|
+
readonly duration: otel.HrTime;
|
|
21
|
+
readonly ended: boolean;
|
|
22
|
+
// readonly resource: Resource;
|
|
23
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
24
|
+
readonly instrumentationLibrary: InstrumentationLibrary;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface OpenTelemetryWorkflowExporter extends Sink {
|
|
28
|
+
export(span: SerializableSpan[]): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Required external dependencies for Workflow interceptor to export spans
|
|
33
|
+
*/
|
|
34
|
+
export interface OpenTelemetrySinks extends Sinks {
|
|
35
|
+
exporter: OpenTelemetryWorkflowExporter;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum SpanName {
|
|
39
|
+
/**
|
|
40
|
+
* Workflow is scheduled by a client
|
|
41
|
+
*/
|
|
42
|
+
WORKFLOW_START = 'StartWorkflow',
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Workflow is client calls signalWithStart
|
|
46
|
+
*/
|
|
47
|
+
WORKFLOW_SIGNAL_WITH_START = 'SignalWithStartWorkflow',
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Workflow run is executing
|
|
51
|
+
*/
|
|
52
|
+
WORKFLOW_EXECUTE = 'RunWorkflow',
|
|
53
|
+
/**
|
|
54
|
+
* Child Workflow is started (by parent Workflow)
|
|
55
|
+
*/
|
|
56
|
+
CHILD_WORKFLOW_START = 'StartChildWorkflow',
|
|
57
|
+
/**
|
|
58
|
+
* Activity is scheduled by a Workflow
|
|
59
|
+
*/
|
|
60
|
+
ACTIVITY_START = 'StartActivity',
|
|
61
|
+
/**
|
|
62
|
+
* Activity is executing
|
|
63
|
+
*/
|
|
64
|
+
ACTIVITY_EXECUTE = 'RunActivity',
|
|
65
|
+
/**
|
|
66
|
+
* Workflow is continuing as new
|
|
67
|
+
*/
|
|
68
|
+
CONTINUE_AS_NEW = 'ContinueAsNew',
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const SPAN_DELIMITER = ':';
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import './runtime'; // Patch the Workflow isolate runtime for opentelemetry
|
|
2
|
+
import * as otel from '@opentelemetry/api';
|
|
3
|
+
import * as tracing from '@opentelemetry/sdk-trace-base';
|
|
4
|
+
import { extractContextFromHeaders, headersWithContext } from '@temporalio/common/lib/otel';
|
|
5
|
+
import {
|
|
6
|
+
ActivityInput,
|
|
7
|
+
ContinueAsNew,
|
|
8
|
+
ContinueAsNewInput,
|
|
9
|
+
DisposeInput,
|
|
10
|
+
Next,
|
|
11
|
+
StartChildWorkflowExecutionInput,
|
|
12
|
+
WorkflowExecuteInput,
|
|
13
|
+
WorkflowInboundCallsInterceptor,
|
|
14
|
+
workflowInfo,
|
|
15
|
+
WorkflowInternalsInterceptor,
|
|
16
|
+
WorkflowOutboundCallsInterceptor,
|
|
17
|
+
} from '@temporalio/workflow';
|
|
18
|
+
import { instrument } from '../instrumentation';
|
|
19
|
+
import { ContextManager } from './context-manager';
|
|
20
|
+
import { SpanName, SPAN_DELIMITER } from './definitions';
|
|
21
|
+
import { SpanExporter } from './span-exporter';
|
|
22
|
+
|
|
23
|
+
export * from './definitions';
|
|
24
|
+
|
|
25
|
+
let tracer: undefined | otel.Tracer = undefined;
|
|
26
|
+
let contextManager: undefined | ContextManager = undefined;
|
|
27
|
+
|
|
28
|
+
function getTracer(): otel.Tracer {
|
|
29
|
+
if (contextManager === undefined) {
|
|
30
|
+
contextManager = new ContextManager();
|
|
31
|
+
}
|
|
32
|
+
if (tracer === undefined) {
|
|
33
|
+
const provider = new tracing.BasicTracerProvider();
|
|
34
|
+
provider.addSpanProcessor(new tracing.SimpleSpanProcessor(new SpanExporter()));
|
|
35
|
+
provider.register({ contextManager });
|
|
36
|
+
tracer = provider.getTracer('@temporalio/interceptor-workflow');
|
|
37
|
+
}
|
|
38
|
+
return tracer;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Intercepts calls to run a Workflow
|
|
43
|
+
*
|
|
44
|
+
* Wraps the operation in an opentelemetry Span and links it to a parent Span context if one is
|
|
45
|
+
* provided in the Workflow input headers.
|
|
46
|
+
*/
|
|
47
|
+
export class OpenTelemetryInboundInterceptor implements WorkflowInboundCallsInterceptor {
|
|
48
|
+
protected readonly tracer = getTracer();
|
|
49
|
+
|
|
50
|
+
public async execute(
|
|
51
|
+
input: WorkflowExecuteInput,
|
|
52
|
+
next: Next<WorkflowInboundCallsInterceptor, 'execute'>
|
|
53
|
+
): Promise<unknown> {
|
|
54
|
+
const context = await extractContextFromHeaders(input.headers);
|
|
55
|
+
return await instrument({
|
|
56
|
+
tracer: this.tracer,
|
|
57
|
+
spanName: `${SpanName.WORKFLOW_EXECUTE}${SPAN_DELIMITER}${workflowInfo().workflowType}`,
|
|
58
|
+
fn: () => next(input),
|
|
59
|
+
context,
|
|
60
|
+
acceptableErrors: (err) => err instanceof ContinueAsNew,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Intercepts outbound calls to schedule an Activity
|
|
67
|
+
*
|
|
68
|
+
* Wraps the operation in an opentelemetry Span and passes it to the Activity via headers.
|
|
69
|
+
*/
|
|
70
|
+
export class OpenTelemetryOutboundInterceptor implements WorkflowOutboundCallsInterceptor {
|
|
71
|
+
protected readonly tracer = getTracer();
|
|
72
|
+
|
|
73
|
+
public async scheduleActivity(
|
|
74
|
+
input: ActivityInput,
|
|
75
|
+
next: Next<WorkflowOutboundCallsInterceptor, 'scheduleActivity'>
|
|
76
|
+
): Promise<unknown> {
|
|
77
|
+
return await instrument({
|
|
78
|
+
tracer: this.tracer,
|
|
79
|
+
spanName: `${SpanName.ACTIVITY_START}${SPAN_DELIMITER}${input.activityType}`,
|
|
80
|
+
fn: async () => {
|
|
81
|
+
const headers = await headersWithContext(input.headers);
|
|
82
|
+
return next({
|
|
83
|
+
...input,
|
|
84
|
+
headers,
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async startChildWorkflowExecution(
|
|
91
|
+
input: StartChildWorkflowExecutionInput,
|
|
92
|
+
next: Next<WorkflowOutboundCallsInterceptor, 'startChildWorkflowExecution'>
|
|
93
|
+
): Promise<[Promise<string>, Promise<unknown>]> {
|
|
94
|
+
return await instrument({
|
|
95
|
+
tracer: this.tracer,
|
|
96
|
+
spanName: `${SpanName.CHILD_WORKFLOW_START}${SPAN_DELIMITER}${input.workflowType}`,
|
|
97
|
+
fn: async () => {
|
|
98
|
+
const headers = await headersWithContext(input.headers);
|
|
99
|
+
return next({
|
|
100
|
+
...input,
|
|
101
|
+
headers,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public async continueAsNew(
|
|
108
|
+
input: ContinueAsNewInput,
|
|
109
|
+
next: Next<WorkflowOutboundCallsInterceptor, 'continueAsNew'>
|
|
110
|
+
): Promise<never> {
|
|
111
|
+
return await instrument({
|
|
112
|
+
tracer: this.tracer,
|
|
113
|
+
spanName: `${SpanName.CONTINUE_AS_NEW}${SPAN_DELIMITER}${input.options.workflowType}`,
|
|
114
|
+
fn: async () => {
|
|
115
|
+
const headers = await headersWithContext(input.headers);
|
|
116
|
+
return next({
|
|
117
|
+
...input,
|
|
118
|
+
headers,
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
acceptableErrors: (err) => err instanceof ContinueAsNew,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export class OpenTelemetryInternalsInterceptor implements WorkflowInternalsInterceptor {
|
|
127
|
+
async dispose(input: DisposeInput, next: Next<WorkflowInternalsInterceptor, 'dispose'>): Promise<void> {
|
|
128
|
+
if (contextManager !== undefined) {
|
|
129
|
+
contextManager.disable();
|
|
130
|
+
}
|
|
131
|
+
await next(input);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets global variables required for importing opentelemetry in isolate
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import { inWorkflowContext } from '@temporalio/workflow';
|
|
6
|
+
|
|
7
|
+
if (inWorkflowContext()) {
|
|
8
|
+
// Required by opentelemetry (pretend to be a browser)
|
|
9
|
+
Object.assign(globalThis, {
|
|
10
|
+
performance: {
|
|
11
|
+
timeOrigin: Date.now(),
|
|
12
|
+
now() {
|
|
13
|
+
return Date.now() - this.timeOrigin;
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
window: globalThis,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as tracing from '@opentelemetry/sdk-trace-base';
|
|
2
|
+
import { ExportResult, ExportResultCode } from '@opentelemetry/core';
|
|
3
|
+
import * as wf from '@temporalio/workflow';
|
|
4
|
+
import { OpenTelemetrySinks, SerializableSpan } from './definitions';
|
|
5
|
+
|
|
6
|
+
const { exporter } = wf.proxySinks<OpenTelemetrySinks>();
|
|
7
|
+
|
|
8
|
+
export class SpanExporter implements tracing.SpanExporter {
|
|
9
|
+
public export(spans: tracing.ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
|
|
10
|
+
exporter.export(spans.map((span) => this.makeSerializable(span)));
|
|
11
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async shutdown(): Promise<void> {
|
|
15
|
+
// Nothing to shut down
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public makeSerializable(span: tracing.ReadableSpan): SerializableSpan {
|
|
19
|
+
return {
|
|
20
|
+
name: span.name,
|
|
21
|
+
kind: span.kind,
|
|
22
|
+
spanContext: span.spanContext(),
|
|
23
|
+
parentSpanId: span.parentSpanId,
|
|
24
|
+
startTime: span.startTime,
|
|
25
|
+
endTime: span.endTime,
|
|
26
|
+
status: span.status,
|
|
27
|
+
attributes: span.attributes,
|
|
28
|
+
links: span.links,
|
|
29
|
+
events: span.events,
|
|
30
|
+
duration: span.duration,
|
|
31
|
+
ended: span.ended,
|
|
32
|
+
instrumentationLibrary: span.instrumentationLibrary,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|