Skip to content

Commit aac02ce

Browse files
committed
Resolves #2444 - detailed traces and metrics for host init
1 parent 935cb7d commit aac02ce

File tree

3 files changed

+62
-24
lines changed

3 files changed

+62
-24
lines changed

src/WebJobs.Script/Diagnostics/MetricEventNames.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ public static class MetricEventNames
77
{
88
// host level events
99
public const string ApplicationStartLatency = "host.application.start";
10-
public const string HostStartupLatency = "host.startup.latency";
1110
public const string ApplicationInsightsEnabled = "host.applicationinsights.enabled";
1211
public const string ApplicationInsightsDisabled = "host.applicationinsights.disabled";
12+
public const string HostStartupLatency = "host.startup.latency";
13+
public const string HostStartupReadFunctionMetadataLatency = "host.startup.readfunctionmetadata.latency";
14+
public const string HostStartupInitializeBindingProvidersLatency = "host.startup.initializebindingproviders.latency";
15+
public const string HostStartupCreateMetadataProviderLatency = "host.startup.createmetadataprovider.latency";
16+
public const string HostStartupGetFunctionDescriptorsLatency = "host.startup.getfunctiondescriptors.latency";
17+
public const string HostStartupPurgeLogDirectoriesLatency = "host.startup.purgelogdirectories.latency";
1318

1419
// function level events
1520
public const string FunctionInvokeLatency = "function.invoke.latency";

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ public void Initialize()
385385

386386
// Allow tests to modify anything initialized by host.json
387387
ScriptConfig.OnConfigurationApplied?.Invoke(ScriptConfig);
388+
TraceWriter.Verbose("Host configuration applied.");
388389

389390
// only after configuration has been applied and loggers have been created, raise the initializing event
390391
HostInitializing?.Invoke(this, EventArgs.Empty);
@@ -406,6 +407,7 @@ public void Initialize()
406407
includeSubdirectories: false, changeTypes: WatcherChangeTypes.Created | WatcherChangeTypes.Changed);
407408

408409
_debugModeFileWatcher.Changed += OnDebugModeFileChanged;
410+
TraceWriter.Verbose("Debug file watch initialized.");
409411

410412
var storageString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
411413
if (storageString == null)
@@ -422,8 +424,12 @@ public void Initialize()
422424
.Where(f => string.Equals(f.Source, EventSources.ScriptFiles, StringComparison.Ordinal))
423425
.Subscribe(e => OnFileChanged(e.FileChangeArguments));
424426

427+
TraceWriter.Verbose("File event source initialized.");
428+
425429
// take a snapshot so we can detect function additions/removals
426430
_directorySnapshot = Directory.EnumerateDirectories(ScriptConfig.RootScriptPath).ToImmutableArray();
431+
432+
TraceWriter.Verbose("Created directory snapshot.");
427433
}
428434

429435
// If a file change should result in a restart, we debounce the event to
@@ -437,45 +443,62 @@ public void Initialize()
437443
_shutdown = Shutdown;
438444
_shutdown = _shutdown.Debounce(500);
439445

440-
// Scan the function.json early to determine the binding extensions used
441-
var functionMetadata = ReadFunctionMetadata(ScriptConfig, TraceWriter, _startupLogger, FunctionErrors, _settingsManager);
446+
Collection<FunctionMetadata> functionMetadata;
447+
using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupReadFunctionMetadataLatency))
448+
{
449+
// Scan the function.json early to determine the binding extensions used
450+
functionMetadata = ReadFunctionMetadata(ScriptConfig, TraceWriter, _startupLogger, FunctionErrors, _settingsManager);
451+
TraceWriter.Verbose("Function metadata read.");
452+
}
453+
442454
var extensionLoader = new ExtensionLoader(ScriptConfig, TraceWriter, _startupLogger);
443455
var usedBindingTypes = extensionLoader.DiscoverBindingTypes(functionMetadata);
444456

445457
var bindingProviders = LoadBindingProviders(ScriptConfig, hostConfigObject, TraceWriter, _startupLogger, usedBindingTypes);
446458
ScriptConfig.BindingProviders = bindingProviders;
459+
TraceWriter.Verbose("Binding providers loaded.");
447460

448461
var coreBinder = bindingProviders.OfType<CoreExtensionsScriptBindingProvider>().First();
449462
coreBinder.AppDirectory = ScriptConfig.RootScriptPath;
450463

451464
// Allow BindingProviders to initialize
452-
foreach (var bindingProvider in ScriptConfig.BindingProviders)
465+
using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupInitializeBindingProvidersLatency))
453466
{
454-
try
467+
foreach (var bindingProvider in ScriptConfig.BindingProviders)
455468
{
456-
bindingProvider.Initialize();
457-
}
458-
catch (Exception ex)
459-
{
460-
// If we're unable to initialize a binding provider for any reason, log the error
461-
// and continue
462-
string errorMsg = string.Format("Error initializing binding provider '{0}'", bindingProvider.GetType().FullName);
463-
TraceWriter.Error(errorMsg, ex);
464-
_startupLogger?.LogError(0, ex, errorMsg);
469+
try
470+
{
471+
bindingProvider.Initialize();
472+
}
473+
catch (Exception ex)
474+
{
475+
// If we're unable to initialize a binding provider for any reason, log the error
476+
// and continue
477+
string errorMsg = string.Format("Error initializing binding provider '{0}'", bindingProvider.GetType().FullName);
478+
TraceWriter.Error(errorMsg, ex);
479+
_startupLogger?.LogError(0, ex, errorMsg);
480+
}
465481
}
482+
TraceWriter.Verbose("Binding providers initialized.");
466483
}
484+
467485
extensionLoader.LoadBuiltinExtensions(usedBindingTypes);
468486

469487
var directTypes = GetDirectTypes(functionMetadata);
470488
extensionLoader.LoadDirectlyReferencedExtensions(directTypes);
471489
extensionLoader.LoadCustomExtensions();
490+
TraceWriter.Verbose("Extension loading complete.");
472491

473492
// Now all extensions have been loaded, the metadata is finalized.
474493
// There's a single script binding instance that services all extensions.
475494
// give that script binding the metadata for all loaded extensions so it can dispatch to them.
476-
var generalProvider = ScriptConfig.BindingProviders.OfType<GeneralScriptBindingProvider>().First();
477-
var metadataProvider = this.CreateMetadataProvider();
478-
generalProvider.CompleteInitialization(metadataProvider);
495+
using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupCreateMetadataProviderLatency))
496+
{
497+
var generalProvider = ScriptConfig.BindingProviders.OfType<GeneralScriptBindingProvider>().First();
498+
var metadataProvider = this.CreateMetadataProvider();
499+
generalProvider.CompleteInitialization(metadataProvider);
500+
TraceWriter.Verbose("Metadata provider created.");
501+
}
479502

480503
// Do this after we've loaded the custom extensions. That gives an extension an opportunity to plug in their own implementations.
481504
if (storageString != null)
@@ -504,7 +527,13 @@ public void Initialize()
504527
};
505528

506529
// read all script functions and apply to JobHostConfiguration
507-
Collection<FunctionDescriptor> functions = GetFunctionDescriptors(functionMetadata);
530+
Collection<FunctionDescriptor> functions;
531+
using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupGetFunctionDescriptorsLatency))
532+
{
533+
functions = GetFunctionDescriptors(functionMetadata);
534+
TraceWriter.Verbose("Function descriptors read.");
535+
}
536+
508537
Collection<CustomAttributeBuilder> typeAttributes = CreateTypeAttributes(ScriptConfig);
509538
string typeName = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", GeneratedTypeNamespace, GeneratedTypeName);
510539

@@ -524,7 +553,11 @@ public void Initialize()
524553

525554
if (ScriptConfig.FileLoggingMode != FileLoggingMode.Never)
526555
{
527-
PurgeOldLogDirectories();
556+
using (metricsLogger.LatencyEvent(MetricEventNames.HostStartupPurgeLogDirectoriesLatency))
557+
{
558+
PurgeOldLogDirectories();
559+
TraceWriter.Verbose("Old log directories purged.");
560+
}
528561
}
529562
}
530563
}

test/WebJobs.Script.Tests/ScriptHostTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,14 +1119,14 @@ public void Initialize_Sanitizes_HostJsonLog()
11191119

11201120
// for formatting
11211121
var hostJson = JObject.Parse(hostJsonSanitized);
1122-
string expectedMessgae = $"Host configuration file read:{Environment.NewLine}{hostJson}";
1122+
string expectedMessage = $"Host configuration file read:{Environment.NewLine}{hostJson}";
11231123

11241124
var logger = loggerProvider.CreatedLoggers.Single(l => l.Category == LogCategories.Startup);
1125-
var logMessage = logger.LogMessages.Single(l => l.FormattedMessage.StartsWith("Host configuration ")).FormattedMessage;
1126-
Assert.Equal(expectedMessgae, logMessage);
1125+
var logMessage = logger.LogMessages.Single(l => l.FormattedMessage.StartsWith("Host configuration file read")).FormattedMessage;
1126+
Assert.Equal(expectedMessage, logMessage);
11271127

1128-
var traceMessage = traceWriter.GetTraces().Single(t => t.Message.StartsWith("Host configuration ")).Message;
1129-
Assert.Equal(expectedMessgae, traceMessage);
1128+
var traceMessage = traceWriter.GetTraces().Single(t => t.Message.StartsWith("Host configuration file read")).Message;
1129+
Assert.Equal(expectedMessage, traceMessage);
11301130
}
11311131

11321132
[Fact]

0 commit comments

Comments
 (0)