diff --git a/packages/interceptors-opentelemetry/src/index.ts b/packages/interceptors-opentelemetry/src/index.ts index 0abcedf97..3a785d87d 100644 --- a/packages/interceptors-opentelemetry/src/index.ts +++ b/packages/interceptors-opentelemetry/src/index.ts @@ -8,6 +8,7 @@ * @module */ +export * from './plugin'; export * from './workflow'; export * from './worker'; export { diff --git a/packages/interceptors-opentelemetry/src/plugin.ts b/packages/interceptors-opentelemetry/src/plugin.ts new file mode 100644 index 000000000..96a4e4737 --- /dev/null +++ b/packages/interceptors-opentelemetry/src/plugin.ts @@ -0,0 +1,47 @@ +import { SpanExporter } from '@opentelemetry/sdk-trace-base'; +import { Resource } from '@opentelemetry/resources'; +import { SimplePlugin } from '@temporalio/plugin'; +import { InjectedSinks, WorkerOptions } from '@temporalio/worker'; +import { OpenTelemetryWorkflowClientInterceptor } from './client' +import { + makeWorkflowExporter, + OpenTelemetryActivityInboundInterceptor, + OpenTelemetryActivityOutboundInterceptor, +} from './worker'; +import { OpenTelemetrySinks } from './workflow'; + +export interface OpenTelemetryPluginOptions { + readonly resource: Resource; + readonly traceExporter: SpanExporter; +} + +export class OpenTelemetryPlugin extends SimplePlugin { + constructor(readonly otelOptions: OpenTelemetryPluginOptions) { + super({ + name: 'OpenTelemetryPlugin', + clientInterceptors: { + workflow: [new OpenTelemetryWorkflowClientInterceptor()], + }, + workerInterceptors: { + workflowModules: [require.resolve('./workflow-interceptors')], + activity: [ + (ctx) => ({ + inbound: new OpenTelemetryActivityInboundInterceptor(ctx), + outbound: new OpenTelemetryActivityOutboundInterceptor(ctx), + }), + ], + }, + }); + } + + configureWorker(options: WorkerOptions): WorkerOptions { + const sinks: InjectedSinks = { + exporter: makeWorkflowExporter(this.otelOptions.traceExporter, this.otelOptions.resource), + }; + options.sinks = { + ...options.sinks, + ...sinks + }; + return super.configureWorker(options); + } +} \ No newline at end of file diff --git a/packages/interceptors-opentelemetry/src/workflow-interceptors.ts b/packages/interceptors-opentelemetry/src/workflow-interceptors.ts new file mode 100644 index 000000000..ddab64494 --- /dev/null +++ b/packages/interceptors-opentelemetry/src/workflow-interceptors.ts @@ -0,0 +1,14 @@ +/** Not a workflow, just interceptors */ + +import { WorkflowInterceptors } from '@temporalio/workflow'; +import { + OpenTelemetryInboundInterceptor, + OpenTelemetryOutboundInterceptor, + OpenTelemetryInternalsInterceptor, +} from './workflow'; + +export const interceptors = (): WorkflowInterceptors => ({ + inbound: [new OpenTelemetryInboundInterceptor()], + outbound: [new OpenTelemetryOutboundInterceptor()], + internals: [new OpenTelemetryInternalsInterceptor()], +}); diff --git a/packages/test/src/test-otel.ts b/packages/test/src/test-otel.ts index 93dcb2e9d..5d4dcb177 100644 --- a/packages/test/src/test-otel.ts +++ b/packages/test/src/test-otel.ts @@ -12,9 +12,9 @@ import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from ' import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import test from 'ava'; import { v4 as uuid4 } from 'uuid'; -import { WorkflowClient } from '@temporalio/client'; +import { Client, WorkflowClient } from '@temporalio/client'; import { OpenTelemetryWorkflowClientInterceptor } from '@temporalio/interceptors-opentelemetry/lib/client'; -import { OpenTelemetryWorkflowClientCallsInterceptor } from '@temporalio/interceptors-opentelemetry'; +import { OpenTelemetryPlugin, OpenTelemetryWorkflowClientCallsInterceptor } from '@temporalio/interceptors-opentelemetry'; import { instrument } from '@temporalio/interceptors-opentelemetry/lib/instrumentation'; import { makeWorkflowExporter, @@ -253,33 +253,18 @@ if (RUN_INTEGRATION_TESTS) { }); await otel.start(); - const sinks: InjectedSinks = { - exporter: makeWorkflowExporter(traceExporter, staticResource), - }; - + const plugin = new OpenTelemetryPlugin({resource: staticResource, traceExporter}); const worker = await Worker.create({ workflowsPath: require.resolve('./workflows'), activities, taskQueue: 'test-otel', - interceptors: { - client: { - workflow: [new OpenTelemetryWorkflowClientCallsInterceptor()], - }, - workflowModules: [require.resolve('./workflows/otel-interceptors')], - activity: [ - (ctx) => ({ - inbound: new OpenTelemetryActivityInboundInterceptor(ctx), - outbound: new OpenTelemetryActivityOutboundInterceptor(ctx), - }), - ], - }, - sinks, + plugins: [plugin], }); - const client = new WorkflowClient({ - interceptors: [new OpenTelemetryWorkflowClientInterceptor()], + const client = new Client({ + plugins: [plugin], }); - await worker.runUntil(client.execute(workflows.smorgasbord, { taskQueue: 'test-otel', workflowId: uuid4() })); + await worker.runUntil(client.workflow.execute(workflows.smorgasbord, { taskQueue: 'test-otel', workflowId: uuid4() })); await otel.shutdown(); const originalSpan = spans.find(({ name }) => name === `${SpanName.WORKFLOW_START}${SPAN_DELIMITER}smorgasbord`); t.true(originalSpan !== undefined);