Skip to content

Add global Sentry.getDynamicSamplingContext function #10119

@Lms24

Description

@Lms24

Problem Statement

Our current state of obtaining the correct DSC is messy and it's easy to get the logic, when to use the DSC from a span vs. from client data vs. the one on the propagation context wrong.

With #10094 we started moving away from creating a DSC from the transaction but this can only be temporary because the frozen DSC is still on the txn.

But what about Scope.getPropagationContext?

After discussing this extensively, our previous solution to consolidate DSC whenever scope.getPropagationContext is called (as described in #10095) has one fundamental flaw: In Otel/Node, the "active span" is not always the span that's on the current scope from which scope.getPropagationContext would be called. Now, we could, theoretically, just call getActiveSpan() within scope.getPropagationContext but arguably, this destroys the semantics and doesn't make much sense in Node.

Solution Brainstorm

The solution is to decouple DynamicSamplingContext and PropagationContext. To obtain all the necessary tracing data, we'll need to call:

  • getCurrentScope().getPropagationContext() for traceparent data
  • getDynamicSamplingContext() for DSC

While it's not one unified call, it's still way easier than conditionally selecting DSC from wherever and it'll allow us to preserve semantics better.

This also has the implication, that we'll remove the dsc field from PropagationContext as it'll no longer be necessary.

Pseudo Code Implementation

credits @mydea

// called from start(inactive)?Span(Manual)?
function afterStartSpan(ctx: TransactionContext): void {
  if (ctx.metadata?.dynamicSamplingContext) {
    const scope = getCurrentScope();
    if (!scope.getFrozenDsc()) {
      scope.setFrozenDsc(ctx.metadata.dynamicSamplingContext);
    }
  }
}

function getDynamicSamplingContext(): DynamicSamplingContext {
  const scope = getCurrentScope();
  if (scope.getFrozenDsc()) {
    return scope.getFrozenDsc();
  }

  if (getActiveSpan()) {
    // set the frozen one if we want to re-introduce freezing:
    // getCurrentScope().setFrozenDsc(...);
    return getDscFromSpan();
  }

  return getDscFromClient(scope.getPropagationContext().traceId, getClient(), scope);
}  

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions