Azure诊断wrt自定义日志和尊重scheduledTransferPeriod

时间:2013-11-05 02:47:18

标签: azure azure-diagnostics

我已经实现了类似于http://blogs.technet.com/b/meamcs/archive/2013/05/23/diagnostics-of-cloud-services-custom-trace-listener.aspx的自己的TraceListener。

我注意到的一件事是,该日志会立即显示在My Azure Table Storage中。我想知道这是预期的自定义跟踪侦听器还是因为我在开发环境中。

我的诊断.wadcfg

<?xml version="1.0" encoding="utf-8"?>
 <DiagnosticMonitorConfiguration configurationChangePollInterval="PT1M""overallQuotaInMB="4096" xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
  <DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Information" />
  <Directories scheduledTransferPeriod="PT1M">
    <IISLogs container="wad-iis-logfiles" />
    <CrashDumps container="wad-crash-dumps" />
  </Directories>
  <Logs bufferQuotaInMB="0" scheduledTransferPeriod="PT30M" scheduledTransferLogLevelFilter="Information" />
</DiagnosticMonitorConfiguration>

我改变了一点方法。现在我在webrole的web配置中定义。我注意到当我在webconfig中将autoflush设置为true时,每件事情都有效,但是scheduleTransferPeriod不受尊重,因为flush方法会推送到表存储。我希望scheduleTransferPeriod在缓冲区满了一定数量的日志条目后触发刷新或触发刷新。然后我也可以在服务器关机时刷新。 CustomTraceListener上是否有任何方法或事件可以监听scheduleTransferPeriod?

  <system.diagnostics>
    <!--http://msdn.microsoft.com/en-us/library/sk36c28t(v=vs.110).aspx
    By default autoflush is false.
    By default useGlobalLock is true.  While we try to be threadsafe, we keep this default for now.  Later if we would like to increase performance we can remove this. see http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.usegloballock(v=vs.110).aspx -->
    <trace>
      <listeners>
        <add name="TableTraceListener"
            type="Pos.Services.Implementation.TableTraceListener, Pos.Services.Implementation"
             />
        <remove name="Default" />
      </listeners>
    </trace>
  </system.diagnostics>

我已将自定义跟踪侦听器修改为以下内容:

namespace Pos.Services.Implementation
{
    class TableTraceListener : TraceListener
    {
#region Fields      

        //connection string for azure storage
        readonly string _connectionString;
        //Custom sql storage table for logs.
        //TODO put in config
        readonly string _diagnosticsTable;

        [ThreadStatic]
        static StringBuilder _messageBuffer;

        readonly object _initializationSection = new object();
        bool _isInitialized;

        CloudTableClient _tableStorage;
        readonly object _traceLogAccess = new object();
        readonly List<LogEntry> _traceLog = new List<LogEntry>();
#endregion

#region Constructors
       public TableTraceListener() : base("TableTraceListener")
        {
            _connectionString = RoleEnvironment.GetConfigurationSettingValue("DiagConnection");
            _diagnosticsTable = RoleEnvironment.GetConfigurationSettingValue("DiagTableName");
        }

#endregion

#region Methods

        /// <summary>
        /// Flushes the entries to the storage table
        /// </summary>
        public override void Flush()
        {
            if (!_isInitialized)
            {
                lock (_initializationSection)
                {
                    if (!_isInitialized)
                    {
                        Initialize();
                    }
                }
            }

            var context = _tableStorage.GetTableServiceContext();
            context.MergeOption = MergeOption.AppendOnly;
            lock (_traceLogAccess)
            {
                _traceLog.ForEach(entry => context.AddObject(_diagnosticsTable, entry));
                _traceLog.Clear();
            }

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

        /// <summary>
        /// Creates the storage table object. This class does not need to be locked because the caller is locked.
        /// </summary>
        private void Initialize()
        {
            var account = CloudStorageAccount.Parse(_connectionString);
            _tableStorage = account.CreateCloudTableClient();
            _tableStorage.GetTableReference(_diagnosticsTable).CreateIfNotExists();
            _isInitialized = true;
        } 

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

 #region Trace and Write Methods
        /// <summary>
        /// Writes the message to a string buffer
        /// </summary>
        /// <param name="message">the Message</param>
        public override void Write(string message)
        {
            if (_messageBuffer == null)
                _messageBuffer = new StringBuilder();

            _messageBuffer.Append(message);
        }

        /// <summary>
        /// Writes the message with a line breaker to a string buffer
        /// </summary>
        /// <param name="message"></param>
        public override void WriteLine(string message)
        {
            if (_messageBuffer == null)
                _messageBuffer = new StringBuilder();

            _messageBuffer.AppendLine(message);
        }

        /// <summary>
        /// Appends the trace information and message
        /// </summary>
        /// <param name="eventCache">the Event Cache</param>
        /// <param name="source">the Source</param>
        /// <param name="eventType">the Event Type</param>
        /// <param name="id">the Id</param>
        /// <param name="message">the Message</param>
        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);
        }

        /// <summary>
        /// Adds the trace information to a collection of LogEntry objects
        /// </summary>
        /// <param name="id">the Id</param>
        /// <param name="eventType">the Event Type</param>
        /// <param name="eventCache">the EventCache</param>
        private void AppendEntry(int id, TraceEventType eventType, TraceEventCache eventCache)
        {
            if (_messageBuffer == null)
                _messageBuffer = new StringBuilder();

            var message = _messageBuffer.ToString();
            _messageBuffer.Length = 0;

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

            if (message.Length == 0)
                return;

            var 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 (_traceLogAccess)
                _traceLog.Add(entry);
        }

#endregion
#endregion
    }
}

2 个答案:

答案 0 :(得分:1)

我看了你提到的博客文章中的源代码。如果您在Details方法的代码中注意到它正在调用Trace.Flush()方法,它实际上是在表存储中编写到目前为止收集的跟踪日志数据。换句话说,自定义跟踪侦听器根本没有从diagnostics.wadcfg文件中获取计划的传输时间。

答案 1 :(得分:0)

此时,我认为没有一个解决方案可以利用scheduledTransferPeriod和自定义日志。因为我想要自己的表模式,我最终生活在即时传输中。在某些时候,我可能会写自己的转移间隔。