0

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

我注意到的一件事是,这些日志会立即显示在我的 Azure 表存储中。我想知道这是否是自定义跟踪侦听器所期望的,还是因为我在开发环境中。

我的诊断.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
    }
}
4

2 回答 2

1

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

于 2013-11-05T18:14:21.407 回答
0

在这一点上,我认为没有利用 scheduleTransferPeriod 和自定义日志的解决方案。因为我想要自己的表模式,所以我最终接受了立即转移。在某些时候,我可能会编写自己的传输间隔。

于 2013-11-16T21:58:15.703 回答