static void

Azure Diagnostics

See MSDN, ScottGu sdk 2.0. NB SDK 2.0 makes this easier.

Instrument the code

Write lots of Trace.TraceEror. For instance, in MVC's Views/Shared/Error.cshtml (destination of [HandleError])

@model System.Web.Mvc.HandleErrorInfo
    ViewBag.Title = "Error";
<hgroup class="title">
    <h1 class="error">Error.</h1>
    <h2 class="error">An error occurred while processing your request.</h2>
    var sb = new System.Text.StringBuilder();
    sb.AppendLine(Request.RawUrl + " " + Request.UserAgent);
    sb.AppendLine(Model.ControllerName + "." + Model.ActionName);
    var s = sb.ToString();


Must have Imports/Import[@moduleName="Diagnostics"]

<?xml version="1.0" encoding="utf-8" >
<ServiceDefinition name="Cloud" xmlns="" schemaVersion="2012-10.1.8">
  <WebRole name="MartinWeb" vmsize="Small">
      <Site name="Web">
          <Binding name="Endpoint1" endpointName="Endpoint1" />
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      <Import moduleName="Diagnostics" />


Link Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString to your storage account

<?xml version="1.0" encoding="utf-8" >
<ServiceConfiguration serviceName="Cloud" xmlns="" osFamily="3" osVersion="*" schemaVersion="2012-10.1.8">
  <Role name="MartinWeb">
    <Instances count="1" />
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=mystorage;AccountKey=zzz" />


Use WebRole.OnStart or just add a diagnostics.wadcfg to the web project with Copy to Output Directory: Copy always. In SDK 2.0 the Role's Configuration tab has an "Enable Diagnostics" checkbox which writes this file out.

Important: the configuration is stored as blobs in wad-control-container, so if it exists delete the blob first

<DiagnosticMonitorConfiguration xmlns=""
 <Logs bufferQuotaInMB="1024"
   scheduledTransferPeriod="PT1M" />
 <WindowsEventLog bufferQuotaInMB="512"
  <DataSource name="System!*" />
  <DataSource name="Application!*" />

Add the trace listener

If you don't use the emulator in Development, and/or use websites for TST/ACC instead of WebRoles, you can just use Web.Release.config with xdt. NB: check the version number if the SDK has changed!

  <system.diagnostics xdt:Transform="Insert">
          type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

Reading the logs

You can read the WADLogsTable table in VS2012 Server Explorer or third party tools- but I haven't seen a good and clear report page yet. A developer report page is easy to do.

WadLog Table Entity

using System;
using Microsoft.WindowsAzure.Storage.Table;
namespace MartinWeb.Cloud
    public class WadLog : TableEntity
        public WadLog()
            EventTickCount = DateTime.UtcNow.Ticks;
            PartitionKey = "0" + EventTickCount;
            RowKey = string.Format("{0}___Role___RoleInstance1___{1:20}___WADLogsLocalQuery", Guid.NewGuid(), EventTickCount);
        public long EventTickCount { get; set; }
        public string DeploymentId { get; set; }
        public string Role { get; set; }
        public string RoleInstance { get; set; }
        public int Level { get; set; }
        public int EventId { get; set; }
        public int Pid { get; set; }
        public int Tid { get; set; }
        public string Message { get; set; }
        public DateTime EventDateTime
            get { return new DateTime(EventTickCount); }


using System;
using System.Collections.Generic;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
namespace MartinWeb.Cloud
    public class WadLogReader
        private readonly string _connectionString;
        public WadLogReader()
            _connectionString =
        private CloudTable FindTable()
            var storageAccount = CloudStorageAccount.Parse(_connectionString);
            var tableClient = storageAccount.CreateCloudTableClient();
            var table = tableClient.GetTableReference("WADLogsTable");
            return table;
        public IEnumerable<WadLog> Query(DateTime start, DateTime? end = null)
            var partitionStart = start.Ticks.ToString("D19");
            var table = FindTable();
            var filter =
                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.GreaterThanOrEqual, partitionStart);
            if (end.HasValue)
                string partitionEnd = end.Value.Ticks.ToString("D19");
                var to =
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.LessThanOrEqual, partitionEnd);
                filter = TableQuery.CombineFilters(filter, TableOperators.And, to);
            var query = new TableQuery<WadLog>()
            return table.ExecuteQuery(query);

Controller Action

public ActionResult Index()
    var logs = new WadLogReader();
    var now = DateTime.UtcNow;
    var result = logs.Query(now.Date.AddDays(-5));
    return View(result);


@model IEnumerable<MartinWeb.Cloud.WadLog>
    ViewBag.Title = "Index";
<h2>Trace logs</h2>
    @foreach (var log in Model)
            <td>@log.EventDateTime.ToString("dd/MM/yyyy HH:mm")</td>
            <td><pre style="max-width:400px;white-space: pre-wrap">@log.Message</pre></td>