Skip to content

Commit 8753b34

Browse files
authored
Add feature switch for diagnostics handler in System.Net.Http (#38765)
1 parent 117c9d6 commit 8753b34

File tree

3 files changed

+51
-32
lines changed

3 files changed

+51
-32
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<linker>
2+
<assembly fullname="System.Net.Http">
3+
<type fullname="System.Net.Http.DiagnosticsHandler">
4+
<method signature="System.Boolean IsEnabled()" body="stub" value="false" feature="System.Net.Http.EnableActivityPropagation" featurevalue="false" />
5+
</type>
6+
</assembly>
7+
</linker>

src/libraries/System.Net.Http/src/System.Net.Http.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
<PropertyGroup Condition=" '$(TargetsBrowser)' == 'true'">
1515
<DefineConstants>$(DefineConstants);TARGETS_BROWSER</DefineConstants>
1616
</PropertyGroup>
17+
<!-- ILLinker settings -->
18+
<PropertyGroup>
19+
<ILLinkDirectory>$(MSBuildThisFileDirectory)ILLink\</ILLinkDirectory>
20+
</PropertyGroup>
21+
<ItemGroup>
22+
<ILLinkSubstitutionsXmls Include="$(ILLinkDirectory)ILLink.Substitutions.xml" />
23+
</ItemGroup>
24+
1725
<ItemGroup>
1826
<Compile Include="System\Net\Http\ByteArrayContent.cs" />
1927
<Compile Include="System\Net\Http\ByteArrayHelpers.cs" />

src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal static bool IsEnabled()
2727
{
2828
// check if there is a parent Activity (and propagation is not suppressed)
2929
// or if someone listens to HttpHandlerDiagnosticListener
30-
return s_enableActivityPropagation && (Activity.Current != null || s_diagnosticListener.IsEnabled());
30+
return Settings.s_activityPropagationEnabled && (Activity.Current != null || Settings.s_diagnosticListener.IsEnabled());
3131
}
3232

3333
// SendAsyncCore returns already completed ValueTask for when async: false is passed.
@@ -58,10 +58,11 @@ private async ValueTask<HttpResponseMessage> SendAsyncCore(HttpRequestMessage re
5858
}
5959

6060
Activity? activity = null;
61+
DiagnosticListener diagnosticListener = Settings.s_diagnosticListener;
6162

6263
// if there is no listener, but propagation is enabled (with previous IsEnabled() check)
6364
// do not write any events just start/stop Activity and propagate Ids
64-
if (!s_diagnosticListener.IsEnabled())
65+
if (!diagnosticListener.IsEnabled())
6566
{
6667
activity = new Activity(DiagnosticsHandlerLoggingStrings.ActivityName);
6768
activity.Start();
@@ -82,26 +83,26 @@ await base.SendAsync(request, cancellationToken).ConfigureAwait(false) :
8283
Guid loggingRequestId = Guid.Empty;
8384

8485
// There is a listener. Check if listener wants to be notified about HttpClient Activities
85-
if (s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityName, request))
86+
if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityName, request))
8687
{
8788
activity = new Activity(DiagnosticsHandlerLoggingStrings.ActivityName);
8889

8990
// Only send start event to users who subscribed for it, but start activity anyway
90-
if (s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityStartName))
91+
if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityStartName))
9192
{
92-
s_diagnosticListener.StartActivity(activity, new ActivityStartData(request));
93+
diagnosticListener.StartActivity(activity, new ActivityStartData(request));
9394
}
9495
else
9596
{
9697
activity.Start();
9798
}
9899
}
99100
// try to write System.Net.Http.Request event (deprecated)
100-
if (s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated))
101+
if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated))
101102
{
102103
long timestamp = Stopwatch.GetTimestamp();
103104
loggingRequestId = Guid.NewGuid();
104-
s_diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated,
105+
diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated,
105106
new RequestData(request, loggingRequestId, timestamp));
106107
}
107108

@@ -132,12 +133,12 @@ await base.SendAsync(request, cancellationToken).ConfigureAwait(false) :
132133
{
133134
taskStatus = TaskStatus.Faulted;
134135

135-
if (s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ExceptionEventName))
136+
if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ExceptionEventName))
136137
{
137138
// If request was initially instrumented, Activity.Current has all necessary context for logging
138139
// Request is passed to provide some context if instrumentation was disabled and to avoid
139140
// extensive Activity.Tags usage to tunnel request properties
140-
s_diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.ExceptionEventName, new ExceptionData(ex, request));
141+
diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.ExceptionEventName, new ExceptionData(ex, request));
141142
}
142143
throw;
143144
}
@@ -146,7 +147,7 @@ await base.SendAsync(request, cancellationToken).ConfigureAwait(false) :
146147
// always stop activity if it was started
147148
if (activity != null)
148149
{
149-
s_diagnosticListener.StopActivity(activity, new ActivityStopData(
150+
diagnosticListener.StopActivity(activity, new ActivityStopData(
150151
response,
151152
// If request is failed or cancelled, there is no response, therefore no information about request;
152153
// pass the request in the payload, so consumers can have it in Stop for failed/canceled requests
@@ -155,10 +156,10 @@ await base.SendAsync(request, cancellationToken).ConfigureAwait(false) :
155156
taskStatus));
156157
}
157158
// Try to write System.Net.Http.Response event (deprecated)
158-
if (s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated))
159+
if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated))
159160
{
160161
long timestamp = Stopwatch.GetTimestamp();
161-
s_diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated,
162+
diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated,
162163
new ResponseData(
163164
response,
164165
loggingRequestId,
@@ -246,29 +247,35 @@ internal ResponseData(HttpResponseMessage? response, Guid loggingRequestId, long
246247
public override string ToString() => $"{{ {nameof(Response)} = {Response}, {nameof(LoggingRequestId)} = {LoggingRequestId}, {nameof(Timestamp)} = {Timestamp}, {nameof(RequestTaskStatus)} = {RequestTaskStatus} }}";
247248
}
248249

249-
private const string EnableActivityPropagationEnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION";
250-
private const string EnableActivityPropagationAppCtxSettingName = "System.Net.Http.EnableActivityPropagation";
250+
private static class Settings
251+
{
252+
private const string EnableActivityPropagationEnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION";
253+
private const string EnableActivityPropagationAppCtxSettingName = "System.Net.Http.EnableActivityPropagation";
251254

252-
private static readonly bool s_enableActivityPropagation = GetEnableActivityPropagationValue();
255+
public static readonly bool s_activityPropagationEnabled = GetEnableActivityPropagationValue();
253256

254-
private static bool GetEnableActivityPropagationValue()
255-
{
256-
// First check for the AppContext switch, giving it priority over the environment variable.
257-
if (AppContext.TryGetSwitch(EnableActivityPropagationAppCtxSettingName, out bool enableActivityPropagation))
257+
private static bool GetEnableActivityPropagationValue()
258258
{
259-
return enableActivityPropagation;
260-
}
259+
// First check for the AppContext switch, giving it priority over the environment variable.
260+
if (AppContext.TryGetSwitch(EnableActivityPropagationAppCtxSettingName, out bool enableActivityPropagation))
261+
{
262+
return enableActivityPropagation;
263+
}
261264

262-
// AppContext switch wasn't used. Check the environment variable to determine which handler should be used.
263-
string? envVar = Environment.GetEnvironmentVariable(EnableActivityPropagationEnvironmentVariableSettingName);
264-
if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
265-
{
266-
// Suppress Activity propagation.
267-
return false;
265+
// AppContext switch wasn't used. Check the environment variable to determine which handler should be used.
266+
string? envVar = Environment.GetEnvironmentVariable(EnableActivityPropagationEnvironmentVariableSettingName);
267+
if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
268+
{
269+
// Suppress Activity propagation.
270+
return false;
271+
}
272+
273+
// Defaults to enabling Activity propagation.
274+
return true;
268275
}
269276

270-
// Defaults to enabling Activity propagation.
271-
return true;
277+
public static readonly DiagnosticListener s_diagnosticListener =
278+
new DiagnosticListener(DiagnosticsHandlerLoggingStrings.DiagnosticListenerName);
272279
}
273280

274281
private static void InjectHeaders(Activity currentActivity, HttpRequestMessage request)
@@ -309,9 +316,6 @@ private static void InjectHeaders(Activity currentActivity, HttpRequestMessage r
309316
}
310317
}
311318

312-
private static readonly DiagnosticListener s_diagnosticListener =
313-
new DiagnosticListener(DiagnosticsHandlerLoggingStrings.DiagnosticListenerName);
314-
315319
#endregion
316320
}
317321
}

0 commit comments

Comments
 (0)