7 min read

 

Microsoft Windows Azure Development Cookbook

Microsoft Windows Azure Development Cookbook

Over 80 advanced recipes for developing scalable services with the Windows Azure platform

        Read more about this book      

(For more resources on this subject, see here.)

The implementation of Windows Azure Diagnostics was changed in Windows Azure SDK v1.3 and it is now one of the pluggable modules that have to be explicitly imported into a role in the service definition file. As Windows Azure Diagnostics persists both its configuration and data to Windows Azure storage, it is necessary to specify a storage service account for diagnostics in the service configuration file. The configuration of Windows Azure Diagnostics is performed at the instance level. The code to do that configuration is at the role level, but the diagnostics configuration for each instance is stored in individual blobs in a container named wad-control-container located in the storage service account configured for Windows Azure Diagnostics.

Initializing the configuration of Windows Azure Diagnostics

The Windows Azure Diagnostics module is imported into a role by the specification of an Import element with a moduleName attribute of Diagnostics in the Imports section of the service definition file (ServiceDefinition.csdef). This further requires the specification, in the service configuration file (ServiceConfiguration.cscfg), of a Windows Azure Storage Service account that can be used to access the instance configuration for diagnostics. This configuration is stored as an XML file in a blob, named for the instance, in a container named wad-control-container in the storage service account configured for diagnostics.

The Diagnostics Agent service is started automatically when a role instance starts provided the diagnostics module has been imported into the role. Note that in Windows Azure SDK versions prior to v1.3, this is not true in that the Diagnostics Agent must be explicitly started through the invocation of DiagnosticMonitor.Start().

On instance startup, the diagnostics configuration for the instance can be set as desired in the overridden RoleEntryPoint.OnStart() method. The general idea is to retrieve the default initial configuration using DiagnosticMonitor.GetDefaultInitialConfiguration() and modify it as necessary before saving it using DiagnosticMonitor.Start(). This name is something of a relic, since Windows Azure SDK v1.3 and later, the Diagnostics Agent service is started automatically.

Another way to modify the diagnostics configuration for the instance is to use RoleInstanceDiagnosticManager.GetCurrentConfiguration() to retrieve the existing instance configuration from wad-control-container. This can be modified and then saved using RoleInstanceDiagnosticManager.SetCurrentConfiguration(). This method can be used both inside and outside the role instance. For example, it can be implemented remotely to request that an on-demand transfer be performed. An issue is that using this technique during instance startup violates the principal that the environment on startup is always the same, as the existing instance configuration may already have been modified. Note that it is not possible to modify the diagnostics configuration for an instance if there is a currently active on-demand transfer.

In this recipe, we will learn how to initialize programmatically the configuration of Windows Azure Diagnostics.

How to do it…

We are going to see how to initialize the configuration for Windows Azure Diagnostics using code. We do this as follows:

  1. Use Visual Studio to create an empty cloud project.
  2. Add a web role to the project (accept the default name of WebRole1).
  3. Add the following assembly reference to the project:

    System.Data.Services.Client

  4. In the WebRole class, replace OnStart() with the following:

    public override bool OnStart()
    {
    WadManagement wadManagement = new WadManagement();
    wadManagement.InitializeConfiguration();

    return base.OnStart();
    }

  5. In the Default.aspx file, replace the asp:Content element named BodyContent with the following:

    <asp:Content ID="BodyContent" runat="server"
    ContentPlaceHolderID="MainContent">
    <div id="xmlInner">
    <pre>
    <asp:label id="xmlLabel" runat="server"/>
    </pre>
    </div>
    </asp:Content>

  6. Add the following using statements to the Default.aspx.cs file:

    using Microsoft.WindowsAzure.ServiceRuntime;

  7. In the Default.aspx.cs file, add the following private members to the _Default class:

    private String deploymentId = RoleEnvironment.DeploymentId;
    private String roleName =
    RoleEnvironment.CurrentRoleInstance.Role.Name;
    private String instanceId =
    RoleEnvironment.CurrentRoleInstance.Id;

  8. In the Default.aspx.cs file, replace Page_Load() with the following:

    protected void Page_Load(object sender, EventArgs e)
    {
    WadManagement wad = new WadManagement();
    String wadConfigurationForInstance =
    wad.GetConfigurationBlob(
    deploymentId, roleName, instanceId);
    xmlLabel.Text =
    Server.HtmlEncode(wadConfigurationForInstance);
    }

  9. Add a class named WadManagement to the project.
  10. Add the following using statements to the WadManagement class:

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

  11. Add the following private members to the WadManagement class:

    private String wadConnectionString =
    "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
    private String wadControlContainerName =
    "wad-control-container";
    private CloudStorageAccount cloudStorageAccount;

  12. Add the following constructor to the WadManagement class:

    public WadManagement()
    {
    cloudStorageAccount = CloudStorageAccount.Parse(
    RoleEnvironment.GetConfigurationSettingValue(
    wadConnectionString));
    }

  13. Add the following methods, retrieving the instance configuration blob from Windows Azure Storage, to the WadManagement class:

    public String GetConfigurationBlob(
    String deploymentId, String roleName, String instanceId)
    {
    DeploymentDiagnosticManager deploymentDiagnosticManager =
    new DeploymentDiagnosticManager(
    cloudStorageAccount, deploymentId);

    String wadConfigurationBlobNameForInstance =
    String.Format("{0}/{1}/{2}", deploymentId, roleName,
    instanceId);
    String wadConfigurationForInstance =
    GetWadConfigurationForInstance(
    wadConfigurationBlobNameForInstance);

    return wadConfigurationForInstance;
    }

    private String GetWadConfigurationForInstance(
    String wadConfigurationInstanceBlobName)
    {
    CloudBlobClient cloudBlobClient =
    cloudStorageAccount.CreateCloudBlobClient();
    CloudBlobContainer cloudBlobContainer =
    cloudBlobClient.GetContainerReference(
    wadControlContainerName);
    CloudBlob cloudBlob = cloudBlobContainer.GetBlobReference(
    wadConfigurationInstanceBlobName);

    String wadConfigurationForInstance =
    cloudBlob.DownloadText();

    return wadConfigurationForInstance;
    }

  14. Add the following method, initializing the configuration of Windows Azure Diagnostics, to the WadManagement class:

    public void InitializeConfiguration()
    {
    String eventLog = "Application!*";
    String performanceCounter =
    @"Processor(_Total)% Processor Time";

    DiagnosticMonitorConfiguration dmc =
    DiagnosticMonitor.GetDefaultInitialConfiguration();

    dmc.DiagnosticInfrastructureLogs.BufferQuotaInMB = 100;
    dmc.DiagnosticInfrastructureLogs.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);
    dmc.DiagnosticInfrastructureLogs.
    ScheduledTransferLogLevelFilter = LogLevel.Verbose;

    dmc.WindowsEventLog.BufferQuotaInMB = 100;
    dmc.WindowsEventLog.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);
    dmc.WindowsEventLog.ScheduledTransferLogLevelFilter =
    LogLevel.Verbose;
    dmc.WindowsEventLog.DataSources.Add(eventLog);

    dmc.Logs.BufferQuotaInMB = 100;
    dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromHours(1);
    dmc.Logs.ScheduledTransferLogLevelFilter =
    LogLevel.Verbose;

    dmc.Directories.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);

    PerformanceCounterConfiguration perfCounterConfiguration
    = new PerformanceCounterConfiguration();
    perfCounterConfiguration.CounterSpecifier =
    performanceCounter;
    perfCounterConfiguration.SampleRate =
    System.TimeSpan.FromSeconds(10);
    dmc.PerformanceCounters.DataSources.Add(
    perfCounterConfiguration);
    dmc.PerformanceCounters.BufferQuotaInMB = 100;
    dmc.PerformanceCounters.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);

    DiagnosticMonitor.Start(cloudStorageAccount, dmc);
    }

How it works…

In steps 1 and 2, we create a cloud project with a web role. We add the required assembly reference in step 3.

In step 4, we modify OnStart(), so that it initializes the configuration of Windows Azure Diagnostics.

In step 5, we modify the default web page, so that it displays the content of the blob storing the instance configuration for Windows Azure Diagnostics. In step 6, we add the required using statement to Default.aspx.cs. In step 7, we add some private members to store the deployment ID, the role name, and the instance ID of the current instance. In step 8, we modify the Page_Load() event handler to retrieve the blob content and display it on the default web page.

In step 9, we add the WadManagement class that interacts with the Windows Azure Blob Service. In step 10, we add the required using statements. In step 11, we add some private members to contain the name of the connection string in the service configuration file, and the name of the blob container containing the instance configuration for Windows Azure Diagnostics. We also add a CloudStorageAccount instance, which we initialize in the constructor we add in step 12.

We then add, in step 13, the two methods we use to retrieve the content of the blob containing the instance configuration for Windows Azure Diagnostics. In GetConfigurationBlob(), we first create the name of the blob. We then pass this into the GetWadConfigurationForInstance() method, which invokes various Windows Azure Storage Client Library methods to retrieve the content of the blob.

In step 14, we add the method to initialize the configuration of Windows Azure Diagnostics for the instance. We first specify the names of the event log and performance counter we want to capture and persist. We then retrieve the default initial configuration and configure capture of the Windows Azure infrastructure logs, Windows Event Logs, basic logs, directories, and performance counters. For each of them, we specify a data buffer size of 100 MB and schedule an hourly transfer of logged data.

For Windows Event Logs, we specify that the Application!* event log should be captured locally and persisted to the storage service. The event log is specified using an XPath expression allowing the events to be filtered, if desired. We can add other event logs if desired. We configure the capture and persistence of only one performance counter—the Processor(_Total)% Processor Time. We can add other performance counters if desired. Two sections at the end of this recipe provide additional details on the configuration of event logs and performance counters.

We specify a transfer schedule for the directories data buffer. The Diagnostics Agent automatically inserts special directories into the configuration: crash dumps for all roles, and IIS logs and IIS failed request logs for web roles. The Diagnostics Agent does this because the actual location of the directories is not known until the instance is deployed. Note that even though we have configured a persistence schedule for crash dumps, they are not captured by default. We would need to invoke the CrashDumps.EnableCollection() method to enable the capture of crash dumps.

LEAVE A REPLY

Please enter your comment!
Please enter your name here