6
6
using System . Linq ;
7
7
using System . Threading ;
8
8
using System . Threading . Tasks ;
9
+ using Microsoft . ApplicationInsights . AspNetCore ;
10
+ using Microsoft . ApplicationInsights . AspNetCore . Extensions ;
11
+ using Microsoft . ApplicationInsights . Extensibility . Implementation . ApplicationId ;
9
12
using Microsoft . Azure . WebJobs . Logging ;
10
13
using Microsoft . Azure . WebJobs . Script . Scale ;
11
14
using Microsoft . Extensions . DependencyInjection ;
@@ -34,6 +37,8 @@ public class WebJobsScriptHostService : IHostedService, IScriptHostManager, IDis
34
37
private int _hostStartCount ;
35
38
private bool _disposed = false ;
36
39
40
+ private static IDisposable _requestTrackingModule ;
41
+
37
42
public WebJobsScriptHostService ( IOptionsMonitor < ScriptApplicationHostOptions > applicationHostOptions , IScriptHostBuilder scriptHostBuilder , ILoggerFactory loggerFactory , IServiceProvider rootServiceProvider ,
38
43
IServiceScopeFactory rootScopeFactory , IScriptWebHostEnvironment scriptWebHostEnvironment , IEnvironment environment ,
39
44
HostPerformanceManager hostPerformanceManager , IOptions < HostHealthMonitorOptions > healthMonitorOptions )
@@ -43,6 +48,9 @@ public WebJobsScriptHostService(IOptionsMonitor<ScriptApplicationHostOptions> ap
43
48
throw new ArgumentNullException ( nameof ( loggerFactory ) ) ;
44
49
}
45
50
51
+ // This will no-op if already initialized.
52
+ InitializeApplicationInsightsRequestTracking ( ) ;
53
+
46
54
_applicationHostOptions = applicationHostOptions ?? throw new ArgumentNullException ( nameof ( applicationHostOptions ) ) ;
47
55
_scriptWebHostEnvironment = scriptWebHostEnvironment ?? throw new ArgumentNullException ( nameof ( scriptWebHostEnvironment ) ) ;
48
56
_rootServiceProvider = rootServiceProvider ;
@@ -144,6 +152,13 @@ private async Task StartHostAsync(CancellationToken cancellationToken, int attem
144
152
145
153
LogInitialization ( localHost , isOffline , attemptCount , ++ _hostStartCount ) ;
146
154
155
+ if ( ! _scriptWebHostEnvironment . InStandbyMode )
156
+ {
157
+ // At this point we know that App Insights is initialized (if being used), so we
158
+ // can dispose this early request tracking module, which forces our new one to take over.
159
+ DisposeRequestTrackingModule ( ) ;
160
+ }
161
+
147
162
await _host . StartAsync ( cancellationToken ) ;
148
163
149
164
if ( ! startupMode . HasFlag ( JobHostStartupMode . HandlingError ) )
@@ -231,6 +246,12 @@ await Utility.DelayWithBackoffAsync(attemptCount, cancellationToken, min: TimeSp
231
246
}
232
247
}
233
248
249
+ private void DisposeRequestTrackingModule ( )
250
+ {
251
+ _requestTrackingModule ? . Dispose ( ) ;
252
+ _requestTrackingModule = null ;
253
+ }
254
+
234
255
public async Task StopAsync ( CancellationToken cancellationToken )
235
256
{
236
257
_startupLoopTokenSource ? . Cancel ( ) ;
@@ -418,6 +439,33 @@ private async Task Orphan(IHost instance, ILogger logger, CancellationToken canc
418
439
}
419
440
}
420
441
442
+ private static void InitializeApplicationInsightsRequestTracking ( )
443
+ {
444
+ if ( _requestTrackingModule != null )
445
+ {
446
+ return ;
447
+ }
448
+
449
+ // Requests may come in before the JobHost has started (like during cold starts), which means
450
+ // they will not be properly tracked by Application Insights because there's nothing listening
451
+ // for them yet. This wires up the request tracking module with default values to catch those
452
+ // events and properly create an Activity. Once the JobHost has started, we dispose this and the
453
+ // JobHost tracking module takes over.
454
+ var module = new RequestTrackingTelemetryModule ( new ApplicationInsightsApplicationIdProvider ( ) )
455
+ {
456
+ CollectionOptions = new RequestCollectionOptions
457
+ {
458
+ TrackExceptions = false ,
459
+ EnableW3CDistributedTracing = true ,
460
+ InjectResponseHeaders = true
461
+ }
462
+ } ;
463
+
464
+ module . Initialize ( null ) ;
465
+
466
+ _requestTrackingModule = module ;
467
+ }
468
+
421
469
protected virtual void Dispose ( bool disposing )
422
470
{
423
471
if ( ! _disposed )
@@ -426,6 +474,7 @@ protected virtual void Dispose(bool disposing)
426
474
{
427
475
_startupLoopTokenSource ? . Dispose ( ) ;
428
476
_hostRestartSemaphore . Dispose ( ) ;
477
+ DisposeRequestTrackingModule ( ) ;
429
478
}
430
479
_disposed = true ;
431
480
}
0 commit comments