Skip to content

Commit

Permalink
feat(otel): Convert exception otel events to sentry errors
Browse files Browse the repository at this point in the history
always set message

oof prettier

add otel context
  • Loading branch information
AbhiPrasad committed Feb 14, 2023
1 parent f8047f6 commit 44b37e3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
49 changes: 48 additions & 1 deletion packages/opentelemetry-node/src/spanprocessor.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { Context } from '@opentelemetry/api';
import { trace } from '@opentelemetry/api';
import type { Span as OtelSpan, SpanProcessor as OtelSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
import { Transaction } from '@sentry/tracing';
import type { DynamicSamplingContext, Span as SentrySpan, TraceparentData, TransactionContext } from '@sentry/types';
import { logger } from '@sentry/utils';
import { isString, logger } from '@sentry/utils';

import { SENTRY_DYNAMIC_SAMPLING_CONTEXT_KEY, SENTRY_TRACE_PARENT_CONTEXT_KEY } from './constants';
import { isSentryRequestSpan } from './utils/is-sentry-request';
Expand Down Expand Up @@ -93,6 +94,12 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
* @inheritDoc
*/
public onEnd(otelSpan: OtelSpan): void {
const hub = getCurrentHub();
if (!hub) {
__DEBUG_BUILD__ && logger.error('SentrySpanProcessor has triggered onEnd before a hub has been setup.');
return;
}

const otelSpanId = otelSpan.spanContext().spanId;
const sentrySpan = SENTRY_SPAN_PROCESSOR_MAP.get(otelSpanId);

Expand All @@ -112,6 +119,46 @@ export class SentrySpanProcessor implements OtelSpanProcessor {
return;
}

otelSpan.events.forEach(event => {
if (event.name !== 'exception') {
return;
}

const attributes = event.attributes;
if (!attributes) {
return;
}

const message = attributes[SemanticAttributes.EXCEPTION_MESSAGE];
const syntheticError = new Error(message as string | undefined);

const stack = attributes[SemanticAttributes.EXCEPTION_STACKTRACE];
if (isString(stack)) {
syntheticError.stack = stack;
}

const type = attributes[SemanticAttributes.EXCEPTION_TYPE];
if (isString(type)) {
syntheticError.name = type;
}

hub.captureException(syntheticError, {
captureContext: {
contexts: {
otel: {
attributes: otelSpan.attributes,
resource: otelSpan.resource.attributes,
},
trace: {
trace_id: otelSpan.spanContext().traceId,
span_id: otelSpan.spanContext().spanId,
parent_span_id: otelSpan.parentSpanId,
},
},
},
});
});

if (sentrySpan instanceof Transaction) {
updateTransactionWithOtelData(sentrySpan, otelSpan);
} else {
Expand Down
40 changes: 40 additions & 0 deletions packages/opentelemetry-node/test/spanprocessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,46 @@ describe('SentrySpanProcessor', () => {
trace_id: otelSpan.spanContext().traceId,
});
});

it('generates Sentry errors from opentelemetry span exception events', () => {
let sentryEvent: any;
let otelSpan: any;

client = new NodeClient({
...DEFAULT_NODE_CLIENT_OPTIONS,
beforeSend: event => {
sentryEvent = event;
return null;
},
});
hub = new Hub(client);
makeMain(hub);

const tracer = provider.getTracer('default');

tracer.startActiveSpan('GET /users', parentOtelSpan => {
tracer.startActiveSpan('SELECT * FROM users;', child => {
child.recordException(new Error('this is an otel error!'));
otelSpan = child as OtelSpan;
child.end();
});

parentOtelSpan.end();
});

expect(sentryEvent).toBeDefined();
expect(sentryEvent.exception).toBeDefined();
expect(sentryEvent.exception.values[0]).toEqual({
mechanism: expect.any(Object),
type: 'Error',
value: 'this is an otel error!',
});
expect(sentryEvent.contexts.trace).toEqual({
parent_span_id: otelSpan.parentSpanId,
span_id: otelSpan.spanContext().spanId,
trace_id: otelSpan.spanContext().traceId,
});
});
});

// OTEL expects a custom date format
Expand Down

0 comments on commit 44b37e3

Please sign in to comment.