diff --git a/package-lock.json b/package-lock.json index de3542dee..dfad9a49a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19479,6 +19479,7 @@ "@opentelemetry/core": "^1.19.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.46.0", "@opentelemetry/sdk-node": "^0.46.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", "@opentelemetry/semantic-conventions": "^1.19.0", "@temporalio/activity": "file:../activity", "@temporalio/client": "file:../client", @@ -21723,6 +21724,7 @@ "@opentelemetry/core": "^1.19.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.46.0", "@opentelemetry/sdk-node": "^0.46.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", "@opentelemetry/semantic-conventions": "^1.19.0", "@temporalio/activity": "file:../activity", "@temporalio/client": "file:../client", diff --git a/packages/interceptors-opentelemetry/src/instrumentation.ts b/packages/interceptors-opentelemetry/src/instrumentation.ts index 833a16955..1df417b34 100644 --- a/packages/interceptors-opentelemetry/src/instrumentation.ts +++ b/packages/interceptors-opentelemetry/src/instrumentation.ts @@ -44,7 +44,7 @@ async function wrapWithSpan( return ret; } catch (err: any) { if (acceptableErrors === undefined || !acceptableErrors(err)) { - span.setStatus({ code: otel.SpanStatusCode.ERROR }); + span.setStatus({ code: otel.SpanStatusCode.ERROR, message: err instanceof Error ? err.message : String(err) }); span.recordException(err); } else { span.setStatus({ code: otel.SpanStatusCode.OK }); diff --git a/packages/test/package.json b/packages/test/package.json index b2424c022..044a46c7e 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -30,6 +30,7 @@ "@opentelemetry/core": "^1.19.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.46.0", "@opentelemetry/sdk-node": "^0.46.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", "@opentelemetry/semantic-conventions": "^1.19.0", "@temporalio/activity": "file:../activity", "@temporalio/client": "file:../client", diff --git a/packages/test/src/test-otel.ts b/packages/test/src/test-otel.ts index 8eaeb46a6..b87925de0 100644 --- a/packages/test/src/test-otel.ts +++ b/packages/test/src/test-otel.ts @@ -8,11 +8,13 @@ import { SpanStatusCode } from '@opentelemetry/api'; import { ExportResultCode } from '@opentelemetry/core'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; import * as opentelemetry from '@opentelemetry/sdk-node'; +import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import test from 'ava'; import { v4 as uuid4 } from 'uuid'; import { Connection, WorkflowClient } from '@temporalio/client'; import { OpenTelemetryWorkflowClientInterceptor } from '@temporalio/interceptors-opentelemetry/lib/client'; +import { instrument } from '@temporalio/interceptors-opentelemetry/lib/instrumentation'; import { makeWorkflowExporter, OpenTelemetryActivityInboundInterceptor, @@ -413,4 +415,37 @@ if (RUN_INTEGRATION_TESTS) { // Importing the otel workflow modules above should patch globalThis t.falsy((globalThis as any).window); }); + + test('instrumentation: Error status includes message and records exception', async (t) => { + const memoryExporter = new InMemorySpanExporter(); + const provider = new BasicTracerProvider(); + provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + provider.register(); + const tracer = provider.getTracer('test-error-tracer'); + + const errorMessage = 'Test error message'; + + await t.throwsAsync( + instrument({ + tracer, + spanName: 'test-error-span', + fn: async () => { + throw new Error(errorMessage); + }, + }), + { message: errorMessage } + ); + + const spans = memoryExporter.getFinishedSpans(); + t.is(spans.length, 1); + + const span = spans[0]; + + t.is(span.status.code, SpanStatusCode.ERROR); + + t.is(span.status.message, errorMessage); + + const exceptionEvents = span.events.filter((event) => event.name === 'exception'); + t.is(exceptionEvents.length, 1); + }); }