-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(node): Simplify SentrySpanProcessor
#11273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import type { Event } from '@sentry/types'; | ||
import { getActiveSpan, getClient, startInactiveSpan, startSpan, withActiveSpan } from '../../src'; | ||
import { cleanupOtel, mockSdkInit } from '../helpers/mockSdkInit'; | ||
|
||
|
@@ -64,7 +65,11 @@ describe('withActiveSpan()', () => { | |
}); | ||
|
||
it('when `null` is passed, should start a new trace for new spans', async () => { | ||
const beforeSendTransaction = jest.fn(() => null); | ||
const transactions: Event[] = []; | ||
const beforeSendTransaction = jest.fn((event: Event) => { | ||
transactions.push(event); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. l: why do we have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. makes it a bit easier to test what is sent than to use |
||
return null; | ||
}); | ||
mockSdkInit({ enableTracing: true, beforeSendTransaction }); | ||
const client = getClient(); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
import type { Context } from '@opentelemetry/api'; | ||
import { ROOT_CONTEXT, trace } from '@opentelemetry/api'; | ||
import type { Span, SpanProcessor as SpanProcessorInterface } from '@opentelemetry/sdk-trace-base'; | ||
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; | ||
import { ROOT_CONTEXT, TraceFlags, trace } from '@opentelemetry/api'; | ||
import type { ReadableSpan, Span, SpanProcessor as SpanProcessorInterface } from '@opentelemetry/sdk-trace-base'; | ||
import { addChildSpanToSpan, getClient, getDefaultCurrentScope, getDefaultIsolationScope } from '@sentry/core'; | ||
import { logger } from '@sentry/utils'; | ||
|
||
|
@@ -46,20 +45,35 @@ function onSpanStart(span: Span, parentContext: Context): void { | |
client?.emit('spanStart', span); | ||
} | ||
|
||
function onSpanEnd(span: Span): void { | ||
function onSpanEnd(span: ReadableSpan): void { | ||
const client = getClient(); | ||
client?.emit('spanEnd', span); | ||
client?.emit('spanEnd', span as Span); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. m: Is this safe? If so, why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is the same as it was before - this is safe because the actual trace code under the hood passes exactly the same class instance to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do realize that it was like this before, but I now wonder whether we can depend on this. But nothing to duke out in this pr! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked the actual implementation in the tracer, and I think it's fine - not sure how we could be even safer here without checking the existence of each and every property we'd expect this to have 😬 which also feels overkill. But we can for sure revisit this! |
||
} | ||
|
||
/** | ||
* Converts OpenTelemetry Spans to Sentry Spans and sends them to Sentry via | ||
* the Sentry SDK. | ||
*/ | ||
export class SentrySpanProcessor extends BatchSpanProcessor implements SpanProcessorInterface { | ||
public constructor() { | ||
super(new SentrySpanExporter()); | ||
export class SentrySpanProcessor implements SpanProcessorInterface { | ||
private _exporter: SentrySpanExporter; | ||
|
||
public constructor() { | ||
setIsSetup('SentrySpanProcessor'); | ||
this._exporter = new SentrySpanExporter(); | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public async forceFlush(): Promise<void> { | ||
this._exporter.flush(); | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public async shutdown(): Promise<void> { | ||
this._exporter.clear(); | ||
} | ||
|
||
/** | ||
|
@@ -72,29 +86,19 @@ export class SentrySpanProcessor extends BatchSpanProcessor implements SpanProce | |
// once we decoupled opentelemetry from SentrySpan | ||
|
||
DEBUG_BUILD && logger.log(`[Tracing] Starting span "${span.name}" (${span.spanContext().spanId})`); | ||
|
||
return super.onStart(span, parentContext); | ||
} | ||
|
||
/** @inheritDoc */ | ||
public onEnd(span: Span): void { | ||
DEBUG_BUILD && logger.log(`[Tracing] Finishing span "${span.name}" (${span.spanContext().spanId})`); | ||
|
||
if (!this._shouldSendSpanToSentry(span)) { | ||
// Prevent this being called to super.onEnd(), which would pass this to the span exporter | ||
public onEnd(span: ReadableSpan): void { | ||
if (span.spanContext().traceFlags !== TraceFlags.SAMPLED) { | ||
DEBUG_BUILD && logger.log(`[Tracing] Finishing unsampled span "${span.name}" (${span.spanContext().spanId})`); | ||
return; | ||
} | ||
|
||
onSpanEnd(span); | ||
DEBUG_BUILD && logger.log(`[Tracing] Finishing span "${span.name}" (${span.spanContext().spanId})`); | ||
|
||
return super.onEnd(span); | ||
} | ||
onSpanEnd(span); | ||
|
||
/** | ||
* You can overwrite this in a sub class to implement custom behavior for dropping spans. | ||
* If you return `false` here, the span will not be passed to the exporter and thus not be sent. | ||
*/ | ||
protected _shouldSendSpanToSentry(_span: Span): boolean { | ||
return true; | ||
this._exporter.export(span); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL, this test only passed "on accident" before (but this shows we are being more "strict" now than we used to).