Adding Tracing Support to the Application

Reference to Exercise 1: Debugging an Application in the Cloud in Azure Toolkit

  1. Global.asax
  2. WebRole.cs
  3. Custome Trace Listener - AzureDiagnosticsTableStorageListener implementation

Global.asax

>>Add System.trace Table Storage Listener At  Application_Start()

The ConfigureTraceListener method retrieves the EnableTableStorageTraceListener configuration setting and, if its value is true, it creates a new instance of the TableStorageTraceListener class, defined in the project that you added to the solution earlier, and then adds it to the collection of available trace listeners. Note that the method also enables the AutoFlush property of the Trace object to ensure that trace messages are written immediately to table storage, allowing you to retrieve them as they occur.

>>Register "RoleEnvironmentChanged" method to reconfig System.trace Table Storage Listener

>>Add "System.Diagnostics.Trace.TraceError(lastError.Message);" at Application_Error()

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace WebApplication1
{
    public class Global : System.Web.HttpApplication
    {

        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            });

            ConfigureTraceListener();

            RoleEnvironment.Changed += RoleEnvironmentChanged;

        }

        private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
        {
            // configure trace listener for any changes to EnableTableStorageTraceListener 
            if (e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName == "EnableTableStorageTraceListener"))
            {
                ConfigureTraceListener();
            }
        }

        private static void ConfigureTraceListener()
        {
            bool enableTraceListener = false;
            string enableTraceListenerSetting = RoleEnvironment.GetConfigurationSettingValue("EnableTableStorageTraceListener");
            if (bool.TryParse(enableTraceListenerSetting, out enableTraceListener))
            {
                if (enableTraceListener)
                {
                    AzureDiagnostics.TableStorageTraceListener listener =
                        new AzureDiagnostics.TableStorageTraceListener("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString")
                        {
                            Name = "TableStorageTraceListener"
                        };
                    System.Diagnostics.Trace.Listeners.Add(listener);
                    System.Diagnostics.Trace.AutoFlush = true;
                }
                else
                {
                    System.Diagnostics.Trace.Listeners.Remove("TableStorageTraceListener");
                }
            }
        }

        void Application_End(object sender, EventArgs e)
        {
            //  Code that runs on application shutdown

        }

        void Application_Error(object sender, EventArgs e)
        {
            // Code that runs when an unhandled error occurs
            var lastError = Server.GetLastError();
            System.Diagnostics.Trace.TraceError(lastError.Message);

        }

        void Session_Start(object sender, EventArgs e)
        {
            // Code that runs when a new session is started

        }

        void Session_End(object sender, EventArgs e)
        {
            // Code that runs when a session ends. 
            // Note: The Session_End event is raised only when the sessionstate mode
            // is set to InProc in the Web.config file. If session mode is set to StateServer 
            // or SQLServer, the event is not raised.

        }

    }
}

WebRole.cs

>>Register "RoleEnvironmentChanging" method to avoid tracing listener configure changing cause web role restart

// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace WebRole1
{
    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += RoleEnvironmentChanging;

            return base.OnStart();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // for any configuration setting change except EnableTableStorageTraceListener
            if (e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName != "EnableTableStorageTraceListener"))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
    }
}

TableStorageTraceListener && LogEntry Class

// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Client;
using System.Threading;

namespace AzureDiagnostics
{
    public class TableStorageTraceListener : TraceListener
    {
        private const string DEFAULT_DIAGNOSTICS_CONNECTION_STRING = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";

        public static readonly string DIAGNOSTICS_TABLE = "DevLogsTable";

        [ThreadStatic]
        private static StringBuilder messageBuffer;

        private object initializationSection = new object();
        private bool isInitialized = false;

        private object traceLogAccess = new object();
        private List<LogEntry> traceLog = new List<LogEntry>();

        private CloudTableClient tableStorage;
        private string connectionString;

        public TableStorageTraceListener()
            : this(DEFAULT_DIAGNOSTICS_CONNECTION_STRING)
        {
        }

        public TableStorageTraceListener(string connectionString)
        {
            this.connectionString = connectionString;
        }

        public override bool IsThreadSafe
        {
            get
            {
                return true;
            }
        }

        public override void Write(string message)
        {
            if (TableStorageTraceListener.messageBuffer == null)
            {
                TableStorageTraceListener.messageBuffer = new StringBuilder();
            }

            TableStorageTraceListener.messageBuffer.Append(message);
        }

        public override void WriteLine(string message)
        {
            if (TableStorageTraceListener.messageBuffer == null)
            {
                TableStorageTraceListener.messageBuffer = new StringBuilder();
            }

            TableStorageTraceListener.messageBuffer.AppendLine(message);
        }

        public override void Flush()
        {
            if (!this.isInitialized)
            {
                lock (this.initializationSection)
                {
                    if (!this.isInitialized)
                    {
                        Initialize();
                    }
                }
            }

            TableServiceContext context = tableStorage.GetDataServiceContext();
            context.MergeOption = MergeOption.AppendOnly;
            lock (this.traceLogAccess)
            {
                this.traceLog.ForEach(entry => context.AddObject(DIAGNOSTICS_TABLE, entry));
                this.traceLog.Clear();
            }

            if (context.Entities.Count > 0)
            {
                context.BeginSaveChangesWithRetries(SaveChangesOptions.None, (ar) =>
                {
                    context.EndSaveChangesWithRetries(ar);
                }, null);
            }
        }

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
        {
            base.TraceData(eventCache, source, eventType, id, data);
            AppendEntry(id, eventType, eventCache);
        }

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data)
        {
            base.TraceData(eventCache, source, eventType, id, data);
            AppendEntry(id, eventType, eventCache);
        }

        public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id)
        {
            base.TraceEvent(eventCache, source, eventType, id);
            AppendEntry(id, eventType, eventCache);
        }

        public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
        {
            base.TraceEvent(eventCache, source, eventType, id, format, args);
            AppendEntry(id, eventType, eventCache);
        }

        public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
        {
            base.TraceEvent(eventCache, source, eventType, id, message);
            AppendEntry(id, eventType, eventCache);
        }

        public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId)
        {
            base.TraceTransfer(eventCache, source, id, message, relatedActivityId);
            AppendEntry(id, TraceEventType.Transfer, eventCache);
        }

        private void Initialize()
        {
            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting(this.connectionString);
            this.tableStorage = account.CreateCloudTableClient();
            this.tableStorage.CreateTableIfNotExist(DIAGNOSTICS_TABLE);
            this.isInitialized = true;
        }

        private void AppendEntry(int id, TraceEventType eventType, TraceEventCache eventCache)
        {
            if (TableStorageTraceListener.messageBuffer == null)
            {
                TableStorageTraceListener.messageBuffer = new StringBuilder();
            }

            string message = TableStorageTraceListener.messageBuffer.ToString();
            TableStorageTraceListener.messageBuffer.Length = 0;

            if (message.EndsWith(Environment.NewLine))
            {
                message = message.Substring(0, message.Length - Environment.NewLine.Length);
            }

            if (message.Length == 0)
            {
                return;
            }
            
            LogEntry entry = new LogEntry()
            {
                PartitionKey = string.Format("{0:D10}", eventCache.Timestamp >> 30),
                RowKey = string.Format("{0:D19}", eventCache.Timestamp),
                EventTickCount = eventCache.Timestamp,
                Level = (int) eventType,
                EventId = id,
                Pid = eventCache.ProcessId,
                Tid = eventCache.ThreadId,
                Message = message
            };

            lock (this.traceLogAccess)
            {
                this.traceLog.Add(entry);
            }
        }        
    }
}

// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------

namespace AzureDiagnostics
{
    using Microsoft.WindowsAzure.StorageClient;

    public class LogEntry : TableServiceEntity
    {
        public long EventTickCount { get; set; }
        public int Level { get; set; }
        public int EventId { get; set; }
        public int Pid { get; set; }
        public string Tid { get; set; }
        public string Message { get; set; }
    }
}

Test project

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
          
        }

        protected void Error(object sender, EventArgs e)
        {
            int i = 0;
            int j = 100 / i;
            Response.Write(j);
        }
    }
}


Note: TraceListeners can be added by configuring them in the system.diagnostics section of the configuration file.

<configuration>
  <system.diagnostics>
    <trace autoflush="true" indentsize="2">
      <listeners>
        <add name="customAzureTableLog" type="AzureDiagnostics.TableStorageTraceListener,AzureDiagnostics">
        </add>
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值