@@ -34,6 +34,9 @@ internal sealed class HostingApplicationDiagnostics
3434 private readonly HostingMetrics _metrics ;
3535 private readonly ILogger _logger ;
3636
37+ // Internal for testing purposes only
38+ internal bool SuppressActivityOpenTelemetryData { get ; set ; }
39+
3740 public HostingApplicationDiagnostics (
3841 ILogger logger ,
3942 DiagnosticListener diagnosticListener ,
@@ -48,6 +51,19 @@ public HostingApplicationDiagnostics(
4851 _propagator = propagator ;
4952 _eventSource = eventSource ;
5053 _metrics = metrics ;
54+
55+ SuppressActivityOpenTelemetryData = GetSuppressActivityOpenTelemetryData ( ) ;
56+ }
57+
58+ private static bool GetSuppressActivityOpenTelemetryData ( )
59+ {
60+ // Default to true if the switch isn't set.
61+ if ( ! AppContext . TryGetSwitch ( "Microsoft.AspNetCore.Hosting.SuppressActivityOpenTelemetryData" , out var enabled ) )
62+ {
63+ return true ;
64+ }
65+
66+ return enabled ;
5167 }
5268
5369 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -88,9 +104,9 @@ public void BeginRequest(HttpContext httpContext, HostingApplication.Context con
88104 var diagnosticListenerActivityCreationEnabled = ( diagnosticListenerEnabled && _diagnosticListener . IsEnabled ( ActivityName , httpContext ) ) ;
89105 var loggingEnabled = _logger . IsEnabled ( LogLevel . Critical ) ;
90106
91- if ( loggingEnabled || diagnosticListenerActivityCreationEnabled || _activitySource . HasListeners ( ) )
107+ if ( ActivityCreator . IsActivityCreated ( _activitySource , loggingEnabled || diagnosticListenerActivityCreationEnabled ) )
92108 {
93- context . Activity = StartActivity ( httpContext , loggingEnabled , diagnosticListenerActivityCreationEnabled , out var hasDiagnosticListener ) ;
109+ context . Activity = StartActivity ( httpContext , loggingEnabled || diagnosticListenerActivityCreationEnabled , out var hasDiagnosticListener ) ;
94110 context . HasDiagnosticListener = hasDiagnosticListener ;
95111
96112 if ( context . Activity != null )
@@ -385,10 +401,18 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
385401 }
386402
387403 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
388- private Activity ? StartActivity ( HttpContext httpContext , bool loggingEnabled , bool diagnosticListenerActivityCreationEnabled , out bool hasDiagnosticListener )
404+ private Activity ? StartActivity ( HttpContext httpContext , bool diagnosticsOrLoggingEnabled , out bool hasDiagnosticListener )
389405 {
406+ // StartActivity is only called if an Activity is already verified to be created.
407+ Debug . Assert ( ActivityCreator . IsActivityCreated ( _activitySource , diagnosticsOrLoggingEnabled ) ,
408+ "Activity should only be created if diagnostics or logging is enabled." ) ;
409+
390410 hasDiagnosticListener = false ;
391411
412+ var initializeTags = ! SuppressActivityOpenTelemetryData
413+ ? CreateInitializeActivityTags ( httpContext )
414+ : ( TagList ? ) null ;
415+
392416 var headers = httpContext . Request . Headers ;
393417 var activity = ActivityCreator . CreateFromRemote (
394418 _activitySource ,
@@ -402,9 +426,9 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
402426 } ,
403427 ActivityName ,
404428 ActivityKind . Server ,
405- tags : null ,
429+ tags : initializeTags ,
406430 links : null ,
407- loggingEnabled || diagnosticListenerActivityCreationEnabled ) ;
431+ diagnosticsOrLoggingEnabled ) ;
408432 if ( activity is null )
409433 {
410434 return null ;
@@ -425,6 +449,47 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
425449 return activity ;
426450 }
427451
452+ private static TagList CreateInitializeActivityTags ( HttpContext httpContext )
453+ {
454+ // The tags here are set when the activity is created. They can be used in sampling decisions.
455+ // Most values in semantic conventions that are present at creation are specified:
456+ // https://github.com/open-telemetry/semantic-conventions/blob/27735ccca3746d7bb7fa061dfb73d93bcbae2b6e/docs/http/http-spans.md#L581-L592
457+ // Missing values recommended by the spec are:
458+ // - url.query (need configuration around redaction to do properly)
459+ // - http.request.header.<key>
460+
461+ var request = httpContext . Request ;
462+ var creationTags = new TagList ( ) ;
463+
464+ if ( request . Host . HasValue )
465+ {
466+ creationTags . Add ( HostingTelemetryHelpers . AttributeServerAddress , request . Host . Host ) ;
467+
468+ if ( HostingTelemetryHelpers . TryGetServerPort ( request . Host , request . Scheme , out var port ) )
469+ {
470+ creationTags . Add ( HostingTelemetryHelpers . AttributeServerPort , port ) ;
471+ }
472+ }
473+
474+ HostingTelemetryHelpers . SetActivityHttpMethodTags ( ref creationTags , request . Method ) ;
475+
476+ if ( request . Headers . TryGetValue ( "User-Agent" , out var values ) )
477+ {
478+ var userAgent = values . Count > 0 ? values [ 0 ] : null ;
479+ if ( ! string . IsNullOrEmpty ( userAgent ) )
480+ {
481+ creationTags . Add ( HostingTelemetryHelpers . AttributeUserAgentOriginal , userAgent ) ;
482+ }
483+ }
484+
485+ creationTags . Add ( HostingTelemetryHelpers . AttributeUrlScheme , request . Scheme ) ;
486+
487+ var path = ( request . PathBase . HasValue || request . Path . HasValue ) ? ( request . PathBase + request . Path ) . ToString ( ) : "/" ;
488+ creationTags . Add ( HostingTelemetryHelpers . AttributeUrlPath , path ) ;
489+
490+ return creationTags ;
491+ }
492+
428493 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
429494 private void StopActivity ( HttpContext httpContext , Activity activity , bool hasDiagnosticListener )
430495 {
0 commit comments