Wed, 21 Apr 2010

Call DiagnosticMonitor.Start() Only Once

[UPDATE 1/27/2011] This post was during the SDK 1.1 timeframe. The current SDK version is 1.3, and this is no longer an issue.

If you’re using the cloud templates in Visual Studio, you’ll see a line in the OnStart() method in WebRole.cs or WorkerRole.cs that looks like this:

DiagnosticMonitor.Start("DiagnosticsConnectionString");

You might be tempted to put this line somewhere else (like in an ASP.NET page), but please resist that temptation. At the moment, if you call DiagnosticMonitor.Start() more than once, you’ll end up with multiple copies of the Windows Azure Diagnostics process. Much like a memory leak, this will sneak up on you over time (as more processes get started), and you’ll eventually starve your role instance of resources.

We’ve seen this come up more than once in customers’ applications, and we have a bug open on our side to prevent duplicate calls to DiagnosticMonitor.Start() from starting multiple copies of the process in the future.

What About Changing Diagnostics Settings Later?

One reason you might be tempted to call DiagnosticMonitor.Start() again is to use different configuration settings. (Maybe based on an admin user’s actions or a specific error condition, you want to ramp up your logging.)

One of the nice things about Windows Azure Diagnostics is that it can be dynamically configured, and you don’t need to call DiagnosticMonitor.Start() again to do that. Here’s some code that runs in an ASP.NET web page and changes the configuration settings for the current role instance:

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Diagnostics.Management;
...

// same connection string used in the call to DiagnosticMonitor.Start() in WebRole.cs
var account = CloudStorageAccount.Parse(
    RoleEnvironment.GetConfigurationSettingValue("DiagnosticsConnectionString"));

// use the current deployment ID
var diagnosticsManager = new DeploymentDiagnosticManager(account, RoleEnvironment.DeploymentId);

// find the RoleInstanceDiagnosticManager for this role instance
var thisInstance = RoleEnvironment.CurrentRoleInstance;
var instanceManager =
    (from manager in diagnosticsManager.GetRoleInstanceDiagnosticManagersForRole(thisInstance.Role.Name)
        where manager.RoleInstanceId == thisInstance.Id
        select manager).Single();

var cfg = instanceManager.GetCurrentConfiguration();
cfg.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
instanceManager.SetCurrentConfiguration(cfg);

Note that changes to your diagnostic configuration are picked up asynchronously by the diagnostic monitor, so you won’t see your changes take effect immediately. Take a look at ConfigurationChangePollInterval to configure how often configuration changes are picked up.

The Bottom Line

If you’re going to use Windows Azure Diagnostics at all in your application, I recommend calling DiagnosticMonitor.Start() exactly once, in your role’s OnStart() method. Then use dynamic configuration to change settings at runtime.