Creating Performance Counters in Azure Worker Roles
I have written a number of work roles and wanted to monitor
these roles. Using the ms-windows framework the best approach is to create a
custom performance counters. That’s fine for a windows hosted service but how
do I do this in an Azure worker role. Plus how do I provide the performance
counters metrics in the azure monitor page.
This blog will explain how.
Now the first bit of code is the performance counter
creation. Seeing as though this is a custom performance counter we will need to
create it on the OnStart method. I created a method called
InstallPerformanceCounters and here is the code below.
public bool InstallPerformanceCounters()
{
if (PerformanceCounterCategory.Exists("ALAzurePerformanceCounter"))
{
PerformanceCounterCategory.Delete("ALAzurePerformanceCounter");
}
if (!PerformanceCounterCategory.Exists("ALAzurePerformanceCounter"))
{
logger.Info("ALAzurePerformanceCounter
performance counter category does not exist.");
CounterCreationDataCollection counters = new CounterCreationDataCollection();
//
1. counter for counting totals: PerformanceCounterType.NumberOfItems64
CounterCreationData totalMessageCounts = new CounterCreationData();
totalMessageCounts.CounterName
= "MessageCount";
totalMessageCounts.CounterHelp
= "Total number of messages
processed";
totalMessageCounts.CounterType = PerformanceCounterType.NumberOfItems64;
counters.Add(totalMessageCounts);
//
create new category with the counters above
logger.Info("Creating ALAzurePerformanceCounter performance
counters");
PerformanceCounterCategory.Create("ALAzurePerformanceCounter", "ALAzurePerformanceCounter
Worker Role", PerformanceCounterCategoryType.MultiInstance, counters);
logger.Info("Created ALAzurePerformanceCounter performance
counters");
}
else
{
}
return true;
}
The second bit of code updates the diagnostic
configuration so we can view the performance counter in the azure portal.
private static void ConfigureDiagnostics()
{
try
{
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));
var roleInstanceDiagnosticManager = CloudAccountDiagnosticMonitorExtensions.CreateRoleInstanceDiagnosticManager(
RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"),
RoleEnvironment.DeploymentId,
RoleEnvironment.CurrentRoleInstance.Role.Name,
RoleEnvironment.CurrentRoleInstance.Id);
var roleDiagnosticMonitorConfiguration =
roleInstanceDiagnosticManager.GetCurrentConfiguration();
//
Copy settings from configuration.
double workerRolePeriod;
if (!double.TryParse(RoleEnvironment.GetConfigurationSettingValue(WorkerRolePeriodName), out workerRolePeriod))
{
Trace.WriteLine("WebRole environment diagnostics error: " + WorkerRolePeriodName + "
parse failed.");
// Set the default to one minute.
workerRolePeriod = 1d;
}
//
Transfer diagnostic information once every webRolePeriod minutes.
TimeSpan transferPeriod = TimeSpan.FromMinutes(workerRolePeriod);
roleDiagnosticMonitorConfiguration.PerformanceCounters.ScheduledTransferPeriod
= transferPeriod;
double workerRoleSampleRate;
if (!double.TryParse(RoleEnvironment.GetConfigurationSettingValue(WorkerRoleSampleRateName), out workerRoleSampleRate))
{
Trace.WriteLine("WorkerRole environment diagnostics error: " + WorkerRoleSampleRateName + " parse failed.");
// Set the default to ten seconds.
workerRoleSampleRate = 10d;
}
roleDiagnosticMonitorConfiguration.PerformanceCounters.DataSources.Clear();
roleDiagnosticMonitorConfiguration.PerformanceCounters.DataSources.Add(
new PerformanceCounterConfiguration()
{
CounterSpecifier = @"\ALAzurePerformanceCounter(azure)\MessageCount",
SampleRate = TimeSpan.FromSeconds(workerRoleSampleRate)
});
roleInstanceDiagnosticManager.SetCurrentConfiguration(roleDiagnosticMonitorConfiguration);
}
catch (RoleEnvironmentException rex)
{
//
The connection string was missing.
Trace.WriteLine("WorkerRole
environment diagnostics error: " +
rex.Message);
logger.ErrorException("WorkerRole:Exception", rex);
}
catch (InvalidOperationException iox)
{
//
Parse of the connection string failed.
Trace.WriteLine("WorkerRole
environment diagnostics error: " +
iox.Message);
logger.ErrorException("WorkerRole:Exception", iox);
}
}
The final code is the OnStart and OnRun whereby the OnStart
is the first method called on initialisation and calls the above methods whilst
the OnRun executes in a loop until shutdown. The OnRun updates the performance
counter in this case it’s a counter.
public override bool OnStart()
{
// Set
the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
try
{
//
Setup to handle service configuration changes at runtime.
//
For information on handling configuration changes
//
see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
//
Not Implemented in this case.
//-RoleEnvironment.Changing
+= this.RoleEnvironmentChanging;
//-RoleEnvironment.Changed
+= this.RoleEnvironmentChanged;
InstallPerformanceCounters();
//
This is a sample worker implementation. Replace with your logic.
DiagnosticMonitorConfiguration diagnosticConfig = DiagnosticMonitor.GetDefaultInitialConfiguration();
//
Transfer diagnostic information once every minute.
TimeSpan transferPeriod = TimeSpan.FromMinutes(1d);
diagnosticConfig.PerformanceCounters.ScheduledTransferPeriod =
transferPeriod;
//
Set the diagnostic monitor configuration.
DiagnosticMonitor.Start(WADConnectionString, diagnosticConfig);
ConfigureDiagnostics();
}
catch (Exception exc)
{
logger.ErrorException("WorkerRole:Exception", exc);
}
return base.OnStart();
}
public override void Run()
{
// This
is a sample worker implementation. Replace with your logic.
logger.Info("PerformanceCounter entry point called");
string Instance = "azure";
try
{
System.Diagnostics.PerformanceCounter
_perfMessageCount = new System.Diagnostics.PerformanceCounter();//"ALAzurePerformanceCounter",
"MessageCount", Instance, false);
if (!PerformanceCounterCategory.InstanceExists(Instance, "ALAzurePerformanceCounter"))
{
_perfMessageCount.CategoryName = "ALAzurePerformanceCounter";
_perfMessageCount.InstanceName = Instance;
_perfMessageCount.CounterName = "MessageCount";
_perfMessageCount.MachineName = ".";
_perfMessageCount.InstanceLifetime = PerformanceCounterInstanceLifetime.Global;
_perfMessageCount.ReadOnly
= false;
}
while (true)
{
_perfMessageCount.Increment();
Thread.Sleep(10000);
logger.Info("Working");
}
}
catch (Exception exc)
{
logger.ErrorException("WorkerRole:Exception", exc);
}
}
For this demonstration the C# code above is sufficient to
illustrate the usage of the performance counter for the worker role.
Now we need to modify the azure worker role configuration.
1: We need to set the azure worker role to at a higher privileges.
2: We need to configure the azure diagnostic storage to an
azure storage account. The azure monitor page diagnostics will look at the
storage to retrieve the data.
3: We need to configure the diagnostic configuration to
include the performance counter that we want to monitor
4: Set Azure Diagnostic to verbose in the Azure Portal.
Azure Worker Role Configuration
Step 1:
Modify ServiceDefinition.csdef
<ServiceDefinition name="ALPerformanceCounter" xmlns="" schemaVersion="2014-01.2.3">
<WorkerRole name="PerformanceCounter" vmsize="Small">
<Runtime executionContext="elevated" />
Step 2:
Modify ServiceConfiguration.Cloud.cscfg to include the
diagnostic azure storage. Make sure you use https!!!
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=alperformance;AccountKey=XXXXX”
/>
Step 3:
Modify diagnostics.wadcfg to include the performance counter
<?xml version="1.0" encoding="utf-8"?>
<DiagnosticMonitorConfiguration configurationChangePollInterval="PT1M" overallQuotaInMB="4096" xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<DiagnosticInfrastructureLogs />
<Directories>
<IISLogs container="wad-iis-logfiles" />
<CrashDumps container="wad-crash-dumps" />
</Directories>
<Logs bufferQuotaInMB="1024" scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Error" />
<PerformanceCounters bufferQuotaInMB="512" scheduledTransferPeriod="PT1M">
<PerformanceCounterConfiguration counterSpecifier="\ALAzurePerformanceCounter(azure)\MessageCount" sampleRate="PT1M" />
</PerformanceCounters>
<WindowsEventLog bufferQuotaInMB="1024" scheduledTransferPeriod="PT1M"
scheduledTransferLogLevelFilter="Error">
<DataSource name="Application!*" />
</WindowsEventLog>
</DiagnosticMonitorConfiguration>
This can also be done in visual studio.
Edit the project worker role.
Step 4:
Inside the Azure portal. Ensure
the monitoring level is verbose.
Step 5:
Add the metric in the dashboard.
Step 6:
View the performance counter in
the monitor page
Step 7:
Select the performance counter to
create a rule.
This allows you to alert the
support desk if there is an issue.
Enjoy.