2013-11-05 2 views
0

http://blogs.technet.com/b/meamcs/archive/2013/05/23/diagnostics-of-cloud-services-custom-trace-listener.aspx과 비슷한 TraceListener를 구현했습니다.Azure 진단에서 사용자 지정 로그를 기록하고 scheduledTransferPeriod를 기리고

내가 알아챈 한 가지는 로그가 My Azure Table Storage에 바로 표시된다는 것입니다. Custom Trace Listeners로 기대되는지, 아니면 개발 환경에 있기 때문에 궁금합니다.

내 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의 구성을 정의하고 있습니다. webconfig에서 autoflush를 true로 설정하면 모든 것이 작동하지만 flush 메서드가 테이블 저장소에 푸시하기 때문에 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 
    } 
} 

답변

1

난 당신이 언급 된 블로그 게시물의 소스 코드를 보았다. Details 메소드의 코드에서 알 수 있듯이 지금까지 수집 된 추적 로그 데이터를 테이블 저장 영역에 기록하는 것은 Trace.Flush() 메소드 호출입니다. 즉, 맞춤 추적 수신기는 diagnostics.wadcfg 파일에서 예약 전송 기간을 전혀 선택하지 않습니다.

+0

Autoflush를 true로 설정하여 매번 푸시하고있었습니다. http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.autoflush(v=vs.110).aspx. – kjsteuer

+0

그러나 auto flush를 false로 설정하면 Flush 메서드가 호출되지 않습니다. 누구 플러시를 트리거 해야하는지 아는 사람 있습니까? – kjsteuer

+0

질문 자체에 코드를 포함시켜 공유 할 수 있습니까? 블로그 게시물에서 flush 메서드는 수동으로 호출됩니다. –

0

이 시점에서 나는 scheduledTransferPeriod 및 사용자 지정 로그를 활용하는 솔루션이 있다고 생각하지 않습니다. 나는 내 자신의 테이블 스키마를 원했기 때문에 즉각적인 이전과 함께 살았다. 어떤 점에서 나는 나 자신의 전송 간격을 쓸 수있다.