0

http://blogs.technet.com/b/meamcs/archive/2013/05/23/diagnostics-of-cloud-services-custom-trace-listener.aspxに似た独自の TraceListener を実装しました。

私が気づいたことの 1 つは、そのログが My Azure Table Storage にすぐに表示されることです。これはカスタム トレース リスナーで予想されることなのか、それとも私が開発環境にいるためなのか疑問に思います。

私のdiagnosics.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 に設定すると、すべてが機能しますが、フラッシュ メソッドがテーブル ストレージにプッシュされるため、scheduledTransferPeriod が受け入れられません。バッファがいっぱいになるなど、特定の数のログ エントリの後に、scheduleTransferPeriod でフラッシュをトリガーするか、フラッシュをトリガーしたいと考えています。次に、サーバーのシャットダウン時にフラッシュすることもできます。scheduleTransferPeriod をリッスンできる CustomTraceListener のメソッドまたはイベントはありますか?

  <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

現時点では、scheduledTransferPeriod とカスタム ログを活用するための解決策はないと思います。私は自分のテーブルスキーマが欲しかったので、すぐに転送することになりました。ある時点で、私は自分の転送間隔を書くかもしれません。

于 2013-11-16T21:58:15.703 に答える