@@ -34,6 +34,9 @@ internal sealed class HostingApplicationDiagnostics
34
34
private readonly HostingMetrics _metrics ;
35
35
private readonly ILogger _logger ;
36
36
37
+ // Internal for testing purposes only
38
+ internal bool SuppressActivityOpenTelemetryData { get ; set ; }
39
+
37
40
public HostingApplicationDiagnostics (
38
41
ILogger logger ,
39
42
DiagnosticListener diagnosticListener ,
@@ -48,6 +51,19 @@ public HostingApplicationDiagnostics(
48
51
_propagator = propagator ;
49
52
_eventSource = eventSource ;
50
53
_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 ;
51
67
}
52
68
53
69
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -88,9 +104,9 @@ public void BeginRequest(HttpContext httpContext, HostingApplication.Context con
88
104
var diagnosticListenerActivityCreationEnabled = ( diagnosticListenerEnabled && _diagnosticListener . IsEnabled ( ActivityName , httpContext ) ) ;
89
105
var loggingEnabled = _logger . IsEnabled ( LogLevel . Critical ) ;
90
106
91
- if ( loggingEnabled || diagnosticListenerActivityCreationEnabled || _activitySource . HasListeners ( ) )
107
+ if ( ActivityCreator . IsActivityCreated ( _activitySource , loggingEnabled || diagnosticListenerActivityCreationEnabled ) )
92
108
{
93
- context . Activity = StartActivity ( httpContext , loggingEnabled , diagnosticListenerActivityCreationEnabled , out var hasDiagnosticListener ) ;
109
+ context . Activity = StartActivity ( httpContext , loggingEnabled || diagnosticListenerActivityCreationEnabled , out var hasDiagnosticListener ) ;
94
110
context . HasDiagnosticListener = hasDiagnosticListener ;
95
111
96
112
if ( context . Activity != null )
@@ -385,10 +401,18 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
385
401
}
386
402
387
403
[ 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 )
389
405
{
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
+
390
410
hasDiagnosticListener = false ;
391
411
412
+ var initializeTags = ! SuppressActivityOpenTelemetryData
413
+ ? CreateInitializeActivityTags ( httpContext )
414
+ : ( TagList ? ) null ;
415
+
392
416
var headers = httpContext . Request . Headers ;
393
417
var activity = ActivityCreator . CreateFromRemote (
394
418
_activitySource ,
@@ -402,9 +426,9 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
402
426
} ,
403
427
ActivityName ,
404
428
ActivityKind . Server ,
405
- tags : null ,
429
+ tags : initializeTags ,
406
430
links : null ,
407
- loggingEnabled || diagnosticListenerActivityCreationEnabled ) ;
431
+ diagnosticsOrLoggingEnabled ) ;
408
432
if ( activity is null )
409
433
{
410
434
return null ;
@@ -425,6 +449,47 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
425
449
return activity ;
426
450
}
427
451
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
+
428
493
[ MethodImpl ( MethodImplOptions . NoInlining ) ]
429
494
private void StopActivity ( HttpContext httpContext , Activity activity , bool hasDiagnosticListener )
430
495
{
0 commit comments