In this technical post, Steve Gordon shares practical guidance on disabling the recording of Activities (spans) in .NET OpenTelemetry instrumentation, highlighting both the motivation and code implementation.

Disabling Recording of an Activity (span) in .NET OpenTelemetry Instrumentation

Author: Steve Gordon

OpenTelemetry Activity Header

Introduction

Steve Gordon, a .NET engineer at Elastic, details his experience building hobby projects to evaluate Elastic’s observability tooling, focusing on pain points related to the .NET instrumentation libraries (System.Diagnostics) for OpenTelemetry compatibility.

Recording Activities in .NET

In .NET, the Activity class represents a span within an OpenTelemetry trace. Typically, the recording and exporting of these spans is determined early, for example when handling incoming HTTP requests in ASP.NET Core. Head sampling is commonly used—such as ratio-based tracing—which controls what percentage of traces are sampled to balance cost and completeness.

If a trace is sampled (the default behavior in the OpenTelemetry SDK), an Activity is created per incoming request. Child activities may be created for sub-operations, e.g., HTTP calls or database activity. However, nuances arise:

  • Tracing decisions can be overridden by upstream services via W3C headers.
  • There are differences between recording a trace and sampling it for export.

Requirement and Use Case

Steve encountered a scenario where he needed to control programmatically if a span (Activity) should be exported. In an ASP.NET Core middleware designed for a callback endpoint, he validated requests against query parameters and an IP allowlist. Invalid requests were either mistakes or potentially malicious, and he wanted to avoid recording or incurring costs for such traces.

Implementation

To prevent recording/exporting an Activity after an initial positive sampling decision, only a couple of code lines are needed. Key technical points:

  • The Activity object has an ActivityTraceFlags property (a [Flags] enum), with a Recorded bit indicating export eligibility.
  • The framework and libraries set trace flags based on sampling.
  • The IsAllDataRequested property signals whether enrichment (tags, links, events) should be captured.

Sample Implementation:

var activity = Activity.Current;
if (activity is not null)
{
    activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;
    activity.IsAllDataRequested = false;
}
Activity.Current = null;

This snippet ensures the current activity is not recorded:

  • The Recorded flag is unset using a bitwise operation.
  • Data enrichment is skipped by setting IsAllDataRequested to false.
  • Setting Activity.Current to null ensures no child spans will attach to the ignored parent activity.

Alternative Designs

An alternative is to use a filtering Processor in the OpenTelemetry SDK (e.g., MyFilteringProcessor). With this, a custom property can be checked during processing to decide export eligibility.

Advantages and disadvantages:

  • Processor approach: Disables recording at the end of an activity, not as early. May result in unnecessary enrichment or overhead.
  • Direct approach: Early check avoids all overhead, better for scenarios with potentially malicious or frequent invalid requests.

Conclusion

The required code to prevent an Activity from being recorded is simple, but the underlying mechanics may not be obvious. This approach is useful for .NET applications using OpenTelemetry where granular control is needed over trace exporting, especially for cost or security reasons.

“Hopefully, this post helps if you find yourself with a similar requirement.” — Steve Gordon


About the Author

Steve Gordon is a Pluralsight author, 7-time Microsoft MVP, and a .NET engineer at Elastic. He maintains the .NET APM agent, contributes to .NET open-source projects, and leads community initiatives, including the .NET South East Meetup group.


If you found this post helpful, consider supporting Steve via Buy Me a Coffee or PayPal.

This post appeared first on “Steve Gordon’s Blog”. Read the entire article here