Disabling Recording of an Activity (span) in .NET OpenTelemetry Instrumentation
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
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 anActivityTraceFlags
property (a [Flags] enum), with aRecorded
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