Recently I've been thinking how can I track amount of threads available for an application hosted in Azure cloud. It was due to early discovered performance issues, which should be addressed sooner than later. Since we've decided to be async-heavy and made many possible breaking changes, solid metrics related to different application domains should be introduced and implemented.
Since we're taking advantage of Application Insights when measuring performance, finding a way to utilize it and measure threads available for our web app seems natural and uncomplicated. Fortunately Microsoft.ApplicationInsights NuGet package contains ITelemetryInitializer, which looks like this:
/// Represents an object that initializes <see cref="T:Microsoft.ApplicationInsights.Channel.ITelemetry" /> objects.
/// The <see cref="T:Microsoft.ApplicationInsights.DataContracts.TelemetryContext" /> instances use <see cref="T:Microsoft.ApplicationInsights.Extensibility.ITelemetryInitializer" /> objects to
/// automatically initialize properties of the <see cref="T:Microsoft.ApplicationInsights.Channel.ITelemetry" /> objects.
public interface ITelemetryInitializer
/// Initializes properties of the specified <see cref="T:Microsoft.ApplicationInsights.Channel.ITelemetry" /> object.
void Initialize(ITelemetry telemetry);
All it needs is to implement Initialize() method.
Worth noting is the fact, that such initializer will be hit by all traces so don't go crazy when using it to log data from external resources etc.
With such interface, creating a custom initializer, which will log information about threads is a piece of cake:
public class AvailableThreadsInitializer : ITelemetryInitializer
public void Initialize(ITelemetry telemetry)
ThreadPool.GetMaxThreads(out workerThreadsMax, out completionPortThreadsMax);
ThreadPool.GetAvailableThreads(out workerThreadsAvailable, out completionPortThreadsMaxAvailable);
telemetry.Context.Properties["Max. threads"] = workerThreadsMax.ToString();
telemetry.Context.Properties["Max. threads(async I/O)"] = completionPortThreadsMax.ToString();
telemetry.Context.Properties["Available threads"] = workerThreadsAvailable.ToString();
telemetry.Context.Properties["Available threads(async I/O)"] = completionPortThreadsMaxAvailable.ToString();
All what is left to do is to add this initializer to the collection of already defined initializers:
Thanks to this change, each trace will have an information about threads available for your application - for sure it will ease diagnosis when something is wrong with your web application.
Thanks to @marekgrabarz for revealing this feature to me!