Skip to content

Commit abb2a10

Browse files
andrewlockclaude
andcommitted
[R&D] Fast-path bail in Activity intercepts when interception disabled
Without this, every Activity.SetTag / AddTag / set_DisplayName / SetStatus / getter call across the host process — for users who haven't opted into interception — would still hit Activity.GetCustomProperty("__dd_span__") in the integration's OnMethodBegin. That's a Dictionary lookup on every intercepted call, paid by every modern .NET 6+ process whose JIT applies our CallTarget rewrites. Add `if (!IsActivityInterceptionEnabled) return GetDefault();` at the top of each Activity-direct intercept (ActivityStartIntegration and ActivityStopIntegration already had it). Brings non-interception per-call cost down to a single bool field read. Verified across the full Windows TFM matrix that interception tests (SubmitsTracesWithInterception) still pass on net48, netcoreapp3.1, net6.0, net7.0, net8.0, net9.0, net10.0; and listener-path tests (SubmitsTraces, SubmitsTracesWithActivitySource) still pass on net6.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 20d8cfe commit abb2a10

10 files changed

Lines changed: 62 additions & 0 deletions

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityAddTagObjectIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public sealed class ActivityAddTagObjectIntegration
4040
/// </summary>
4141
internal static CallTargetState OnMethodBegin<TTarget, TKey, TValue>(TTarget instance, TKey key, TValue value)
4242
{
43+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
44+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
45+
{
46+
return CallTargetState.GetDefault();
47+
}
48+
4349
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4450
if (scope is not null)
4551
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityAddTagStringIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public sealed class ActivityAddTagStringIntegration
3939
/// </summary>
4040
internal static CallTargetState OnMethodBegin<TTarget, TKey, TValue>(TTarget instance, TKey key, TValue value)
4141
{
42+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
43+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
44+
{
45+
return CallTargetState.GetDefault();
46+
}
47+
4248
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4349
if (scope is not null)
4450
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityDisplayNameGetterIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public sealed class ActivityDisplayNameGetterIntegration
3939
/// </summary>
4040
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
4141
{
42+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
43+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
44+
{
45+
return CallTargetState.GetDefault();
46+
}
47+
4248
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4349
if (scope is not null)
4450
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityDisplayNameIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ public sealed class ActivityDisplayNameIntegration
3838
/// </summary>
3939
internal static CallTargetState OnMethodBegin<TTarget, TValue>(TTarget instance, TValue value)
4040
{
41+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
42+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
43+
{
44+
return CallTargetState.GetDefault();
45+
}
46+
4147
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4248
if (scope is not null)
4349
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivitySetStatusIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ public sealed class ActivitySetStatusIntegration
4343
/// <typeparam name="TDescription">string type</typeparam>
4444
internal static CallTargetState OnMethodBegin<TTarget, TStatusCode, TDescription>(TTarget instance, TStatusCode statusCode, TDescription description)
4545
{
46+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
47+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
48+
{
49+
return CallTargetState.GetDefault();
50+
}
51+
4652
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4753
if (scope is not null)
4854
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivitySetTagIntegration.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ public sealed class ActivitySetTagIntegration
4040
/// </summary>
4141
internal static CallTargetState OnMethodBegin<TTarget, TKey, TValue>(TTarget instance, TKey key, TValue value)
4242
{
43+
// Fast-path bail when interception isn't enabled. Without this check, every Activity.SetTag
44+
// call across the host process would hit the Activity custom-property lookup on the next
45+
// line — pure overhead for users who haven't opted into the interception path.
46+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
47+
{
48+
return CallTargetState.GetDefault();
49+
}
50+
4351
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4452
if (scope is not null)
4553
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityStatusDescriptionGetterIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public sealed class ActivityStatusDescriptionGetterIntegration
4040
/// </summary>
4141
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
4242
{
43+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
44+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
45+
{
46+
return CallTargetState.GetDefault();
47+
}
48+
4349
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4450
if (scope is not null)
4551
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityStatusGetterIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public sealed class ActivityStatusGetterIntegration
4141
/// </summary>
4242
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
4343
{
44+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
45+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
46+
{
47+
return CallTargetState.GetDefault();
48+
}
49+
4450
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4551
if (scope is not null)
4652
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityTagObjectsGetterIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ public sealed class ActivityTagObjectsGetterIntegration
4343
/// </summary>
4444
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
4545
{
46+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
47+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
48+
{
49+
return CallTargetState.GetDefault();
50+
}
51+
4652
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4753
if (scope is not null)
4854
{

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Activity/ActivityTagsGetterIntegration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public sealed class ActivityTagsGetterIntegration
4242
/// </summary>
4343
internal static CallTargetState OnMethodBegin<TTarget>(TTarget instance)
4444
{
45+
// Fast-path bail when interception isn't enabled — see ActivitySetTagIntegration for rationale.
46+
if (!Tracer.Instance.Settings.IsActivityInterceptionEnabled)
47+
{
48+
return CallTargetState.GetDefault();
49+
}
50+
4551
var scope = ActivityCustomPropertyAccessor<TTarget>.GetScope(instance);
4652
if (scope is not null)
4753
{

0 commit comments

Comments
 (0)