Everything about Web and Network Monitoring

Home > Industry Info > Application Performance Management > Gathering Diagnostics from Windows Azure

Gathering Diagnostics from Windows Azure

All systems require a degree of monitoring. We monitor on premise installations for usage, performance, outages, tracing, and for a multitude of other reasons. Services which are deployed on premise operate in a controlled environment. The organisation’s IT team is very much aware of what systems are running on the organisation’s servers. It is an environment which can be managed by the organisation’s own IT team. On the contrary cloud environments tend to be disruptive by nature. Thus in cloud environments monitoring is crucial.

In this article we will walk through the steps required to :

  • configure a Windows Azure application  for the gathering of data for diagnostic purposes;
  • configure the application to persist the gathered data in a Windows Azure Storage Account;
  • read the data and post to your Monitis Account.

 

Configure the Diagnostic Monitor from within an Windows Azure Role.

 

As depicted in Figure 1 below a Diagnostic Monitor is associated with each Windows Azure Role. By default the Diagnostic Monitor will gather trace logs, infrastructure logs, and IIS logs. The diagnostic data is stored in the local storage of the Windows Azure Instance. Local storage is not persistent across deployments of an application. Thus the diagnostic data should be moved to persistent storage such as the Windows Azure Storage Account to be accessed at will. We will give examples below.

 

 

Figure 1 – Windows Azure Role

 

 

For the purpose of this example we will create a simple Windows Azure Application within Microsoft Visual Studio 2010.

Step 1 – Create a Windows Azure Project using C#.

Select Cloud from the list of installed templates.

 

Figure 2 – Create a Windows Azure Project

 

 

 

Step 2 – Select ASP.Net Web Role

 

Figure 3 – Select ASP.NET Web Role

Step 3 – Rename the Web Role to MonitisWebRole1

By default the project will contain a Web Role. A Web Role can be used to deliver the user interface elements of an application. Rename WebRole1 to MonitisWebRole1.

Figure 4 – A default project has been created. Note that the project contains 1 Web Role

 

The renamed Web Role is displayed below

Figure 5 – Web Role has been renamed

 

As can be seen in Figure 4 above the Web Role contains ASPX files and a WebRole class. In this example the WebRole class is triggered on startup of the application. This simple default web application can be executed within your local environment i.e. within the Windows Azure Compute Emulator.

Figure 6 – The default web application

 

 

 

 

 

 

Step 4 – Configure the Diagnostic Monitor for this application

 

Configure the diagnostic monitor from within the class WebRole.cs.  Create a method called ConfigureDiagnosticMonitor to hold the configuration settings of the Diagnostic Monitor. Call the method from within the OnStart method which runs code which initializes a role instance.

//The connection string is defined within the file ServiceConfiguration.Cloud.cscfg

private readonly string wadConnectionString = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";

public override bool OnStart()

{

this.ConfigureDiagnosticMonitor();

return base.OnStart();

}

private void ConfigureDiagnosticMonitor()

{

//Get reference to the initial default configuration.

//Use this reference to effect changes to the default configuration

DiagnosticMonitorConfiguration dMC =

DiagnosticMonitor.GetDefaultInitialConfiguration();

//Configure monitoring of a Windows performance counter

//Add it to the configuration

PerformanceCounterConfiguration pCC = new PerformanceCounterConfiguration();

pCC.CounterSpecifier = @"\Processor(_Total)\% Processor Time";

//get a reading every 10 seconds

pCC.SampleRate = System.TimeSpan.FromSeconds(10d);

dMC.PerformanceCounters.DataSources.Add(pCC);

//trasfer scheduled to every 1 minute

dMC.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(1d);

//Start the diagnostic monitor

DiagnosticMonitor.Start(wadConnectionString, dMC);

}

On executing the application the Diagnostic Monitor will gather Processer Time data and store it in the local storage of the Web Role. At 1 minute intervals the data will be transfered to persistent storage.

Now proceed to set the Instance Count of the Web Role to 2. When the application is deployed 2 instances of the Web Role will be launched by Windows Azure.

 

 

 

 

Step 5 – Specify the number of role instances to deploy

 

Figure 7 – Set the Instance Count to 2

Click on MonitisWebRole1 to access its configuration settings. Set the Instance Count to 2. Diagnostic data will be gathered for both instances. Figure 8 below displays data gathered from 2 instances.

 

Step 6 – Define the Windows Azure Storage account.

 

The connection string which determines the storage location where diagnostics data will be stored is set within your ServiceConfiguration.cscfg

Whilst working within your development environment the development storage on the local envrioment can be used.

The connection string for persistent storage of diagnostics data can be set to local Development Storage during the development cycle of the application

<ConfigurationSettings>

<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"   value="UseDevelopmentStorage=true" />

</ConfigurationSettings>

Once the application is ready for deployment onto Windows Azure is is essential to point the persistent storage to your Windows Azure Storage Account.

For persistent storage of diagnostics data on the cloud, set the connection string to point to your cloud storage account

<ConfigurationSettings>

<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=http;

AccountName=accountName;

AccountKey=accountKey" />

</ConfigurationSettings>

The screenshot below depicts data from table WADPerformanceCountersTable. The table will be created in the Windows Azure Storage account to which the Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString points.

 

Figure 8  – Performance Counter data which has been gathered for 2 instances

 

 

Read the data and post to your Monitis Account.

 

Thus far we have created an ASP.NET Web Application which contains 1 Web Role. The Web Role serves to provide the user interface. We have configured the Diagnostic Monitor to collect CPU utilization perforance counter data. This data will be persisted in the table WADPerformanceCountersTable in the Windows Azure storage account which is specified within the file ServiceConfiguration.cscfg

 

Step 1 – Create a Worker Role

 

Create a Worker Role to execute a background process which will:

  • create a custom monitor within a Monitis account
  • read the data from table WADPerformanceCountersTable
  • post the data to the custom monitor

 

Figure 9  – Click on Roles and add a Worker Role project.

 

 

 

 

 

 

 

 

Select C#, set the name of the Worder Role and press Add

Figure 10  – Adding a Worker Role

The Worker Role is now created as displayed in the Solution Explorer below.

Figure 11  – Worker Role created

Proceed to place the following code within the class WorkerRole.cs

Step 2 – Create the custom monitor within Monitis

 

Place the following code within the Run method of class WorkerRole

Add the following class variables. The apiKey and secretKey values have to be retrieved from yoru Monitis account.

private readonly string wadConnString = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";

//You API key and Secret Key

private String apiKey = "2C73GGQ8QGBKVGPJI9R5U4M811";

private String secretKey = "35JC0OC26OS2FV5DBKED16UF31";

private String monitorAbailableMemoryID;

Add the following code to the Run method

public override void Run()

{

//request authorisation token from your Monitis account

String authToken = requestAuthToken();

//add a custom monitor to you Monitis account and get the id of the custom Monitor

monitorAbailableMemoryID = addCustomMonitor1(authToken);

}//end Run

Call the method requestAuthToken to retrieve a security token from Monitis. This token will be used to post requests to the Monitis service.  Place the following code within WorkerRole class

private String requestAuthToken()

{

String url = "http://www.monitis.com/api?action=authToken&apikey=" + apiKey +

"&secretkey=" + secretKey;

WebRequest request = WebRequest.Create(url);

request.Method = "GET";

WebResponse response = request.GetResponse();

Stream dataStream = response.GetResponseStream();

StreamReader reader = new StreamReader(dataStream);

string responseFromServer = reader.ReadToEnd();

response.Close();

String authToken = DissectAuthString("authToken", responseFromServer);

return authToken;

}//end requestAuthToken

The method DissectAuthString is called from by methos RequestAuthToken

private String DissectAuthString(String keyString, String cString)

{

String dissected = "";

cString = cString.Remove(0, keyString.Length + 5);

int pos = cString.IndexOf("\"}");

dissected = cString.Remove(pos, 2);

return dissected;

}

The following method uses the supplied token to create a custom monitor and returns the ID of the monitor. The ID of the monitor will be used to identify the monitor to which data will be posted. This is essential as more than one custom monitor may be created within a Monitis account.

 

 

private String addCustomMonitor(String authToken)

{

String url = "http://www.monitis.com/customMonitorApi";

String monitorParams =     "PerfCtrs_data:ProcessorTime:Processor+time+records:3:false;";

String resultParams = "processorTime:ProcessorTime:N%2FA:2;";

String name = "Processor Time";

String tag = "[perfctrs+processortime]";

//build the request

WebRequest request = WebRequest.Create(url);

request.Method = "POST";

String postData = "apikey=" + apiKey + "&validation=token&authToken=" + authToken + "&timestamp=" + "2012-03-09 20:00:00" + "&action=addMonitor&monitorParams=" + monitorParams + "&resultParams=" + resultParams + "&name=" + name + "&tag=" + tag;

byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);

request.ContentType = "application/x-www-form-urlencoded";

request.ContentLength = byteArray.Length;

Stream dataStream = request.GetRequestStream();

dataStream.Write(byteArray, 0, byteArray.Length);

dataStream.Close();

//get the response

WebResponse response = request.GetResponse();

dataStream = response.GetResponseStream();

StreamReader reader = new StreamReader(dataStream);

String responseFromServer = reader.ReadToEnd();

response.Close();

return DissectMonitorIDFromStatusString1("status\":\"ok\",\"data",                                             responseFromServer);

}// end addCustomMonitor

The following method is called from method addCustomMonitor

private String DissectMonitorIDFromStatusString1(String keyString, String cString)

{

String dissected = "";

cString = cString.Remove(0, keyString.Length + 4);

int pos = cString.IndexOf("}");

dissected = cString.Remove(pos, 1);

return dissected;

}

At this stage the application can be executed within the local environment. The Worker Role would retrieve an authorisation token from Monitis and use the token to create a custom monitor within Monitis

Figure 12  – Custom Monitor created by method addCustomMonitor

 

Step 3 – Read data from storage and post to custom monitor

 

Amend the Run method.  Add code to post data to your custom monitor.

public override void Run()

{

//request authorisation token from your Monitis account

String authToken = requestAuthToken();

//add a custom monitor to you Monitis account and get the id of the custom Monitor

monitorAbailableMemoryID = addCustomMonitor1(authToken);

while (true)

{

//sleep for 5 minutes

Thread.Sleep(300000);

//loop through the diagnostic data and post to custom monitor

loopThroughData(authToken);

}

}//end Run

private void loopThroughData(String _token)

{

double testTime;

//get referene to the cloud storage account

CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue(wadConnString));

CloudTableClient cloudTableClient = cloudStorageAccount.CreateCloudTableClient();

//get ticks as at previous 10 minutes

DateTime now = DateTime.UtcNow;

DateTime tenMinutesAgo = now.AddMinutes(-10);

string partitionKeyNow = string.Format("0{0}", now.Ticks.ToString());

string partitionKeyTenMinutesAgo = string.Format("0{0}",   tenMinutesAgo.Ticks.ToString());

TableServiceContext tableServiceContext = cloudTableClient.GetDataServiceContext();

tableServiceContext.ResolveType = (unused) => typeof(WadPerformanceCountersTable);

//retrieve rows generated during the last 10 mminutes

CloudTableQuery<WadPerformanceCountersTable> cloudTableQuery =

(from entity in tableServiceContext.CreateQuery<WadPerformanceCountersTable>("WADPerformanceCountersTable") where entity.PartitionKey.CompareTo(partitionKeyNow) < 0 && entity.PartitionKey.CompareTo(partitionKeyTenMinutesAgo) > 0 select entity).Take(1000).AsTableServiceQuery();

List<WadPerformanceCountersTable> performanceCountersEntitiesList = null;

try

{

performanceCountersEntitiesList =  cloudTableQuery.Execute().ToList<WadPerformanceCountersTable>();

}

catch (DataServiceQueryException dsqe)

{

System.Diagnostics.Trace.TraceError(dsqe.Message);

}

//loop through performance counter records and post data to custom monitor

foreach (WadPerformanceCountersTable perfCounterRecord in performanceCountersEntitiesList)

{

testTime = (perfCounterRecord.EventDateTime - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;

testTime = Math.Ceiling(testTime) * 1000;

postValue(_token, performanceCounterMonitorID, perfCounterRecord.CounterValue.ToString(), testTime.ToString(), "processorTime");

}

}//end loopThroughData

Method loopThroughData calls the following method to post data to the Monitis Service.

private void postValue(String authToken, String _monitorId, String _valueToPost, String _checkTime, String _resultType)

{

String url = "http://www.monitis.com/customMonitorApi";

String action = "addResult";

String results = _resultType + ":" + _valueToPost + ";";

String unixDate = _checkTime;

WebRequest request = WebRequest.Create(url);

request.Method = "POST";

request.ContentType = "application/x-www-form-urlencoded";

String postData = "apikey=" + apiKey + "&validation=token&authToken=" + authToken + "&timestamp=" + "2012-03-11 10:00:00" + "&version=2" + "&action=" + action + "&monitorId=" + _monitorId + "&checktime=" + unixDate + "&results=" + results;

byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);

request.ContentType = "application/x-www-form-urlencoded";

request.ContentLength = byteArray.Length;

Stream dataStream = request.GetRequestStream();

dataStream.Write(byteArray, 0, byteArray.Length);

dataStream.Close();

//get the response

WebResponse response = request.GetResponse();

dataStream = response.GetResponseStream();

StreamReader reader = new StreamReader(dataStream);

String responseFromServer = reader.ReadToEnd();

response.Close();

}//end postValue

On executing the Windows Azure application which we have created above:

  • CPU utilization will be recorded into persistent storage
  • A custom monitor will be created
  • Data will be posted to the custom monitor

 

 

 

 

 

The image below displays the outcome of all the above

Figure 13  – Custom Monitor populated with Processor Time

 

 

 

 

About zhirayr