2013-09-27 14 views
9

Gibt es eine Standardmethode zum Protokollieren von Ausnahmen mit ETW?Was ist der beste Weg, Ausnahmen mit ETW zu protokollieren?

Soweit ich gesehen habe, ist die einzige Möglichkeit, dies zu tun, die Nachricht und möglicherweise die innere Ausnahmebedingungsnachricht zu protokollieren, da es keine stark typisierten Parameter für den Ausnahmetyp gibt.

Antwort

1

ein zusätzliches Ereignis verwenden und dieses Ereignis im catch-Block ausgelöst und die Ausnahmemeldung als Parameter für das Ereignis

[Event(1, Message = "Application Falure: {0}", Level = EventLevel.Error, Keywords = Keywords.Diagnostic)] 
public void Failure(string message) 
{ 
    if (this.IsEnabled()) 
    { 
     this.WriteEvent(1, message); 
    } 
} 

Spiel mit dem Level-und Keyword passieren zu steuern, wenn Sie es anmelden wollen, dass die Zeit oder nicht.

+0

Da kann man nicht stark Ausnahmen gegen den Eventsource-Typ verwenden würde ich am besten, es einfach sein Aufruf wie folgt: EventSource.Log.Failure (MyException.ToString())? – jaffa

+0

das wäre ok. – magicandre1981

1

ETW ist nicht .NET-spezifisch, daher wird es keine stark typisierte .NET-spezifische API geben, um .net-Ausnahmen zu protokollieren. Sie würden stattdessen Ihre eigene stark typisierte API erstellen. Dies ist die Idee hinter Semantic Logging und dem Semantic Logging Application Block.

+0

also am Ende des Tages, um ETW nur ​​primitive Datentypen, Strings und Zahlen (in Form von Strings) verwendet werden können? Ist das reine Serialisieren der Exception in eine Zeichenfolge ausreichend? Oder gibt es ein Muster für Nicht -.net-Anwendungen, um Ausnahmen zu verfolgen? – BozoJoe

+1

ETW ist eine binäre Nutzlast und unterstützt Strukturen Ihrer Definition. http://msdn.microsoft.com/en-us/library/windows/desktop/aa382774(v=vs.85).aspx Es ist nur, dass, wenn Sie diese Route gehen, Sie einen benutzerdefinierten Decoder schreiben müssen. Im .NET-Fall gibt es bereits eine gut definierte, die vom .NET-Team bereitgestellt wird. Wie viele andere Dinge im systemeigenen Code gibt es jedoch mehrere Möglichkeiten. C++ Ausnahmen? SEH-Ausnahmen? usw. Der interessanteste Teil einer Ausnahme ist der Callstack (und seine EIPs, um Zeilennummern zu erhalten), der von ETW standardisiert ist, und sein Stackwalker. Alle darüber hinausgehenden Informationen sind Ihr Anruf. – mjsabby

17

Alle CLR-Ausnahmen (die ersten und diejenigen, die möglicherweise zu einem Abbruch der Anwendung führen) werden vom CLR-Laufzeitanbieter bei Aktivierung in ETW protokolliert.

Dies ist ein vollständig "strukturiertes" Ereignis MIT Callstacks (wenn Sie sie wollen). In der Tat können Sie eine Überwachungsanwendung mit dem Traceevent NuGet Paket schreiben (Install-Package Microsoft.Diagnostics.Tracing.TraceEvent)

Ich bin Einfügen Überwachung Code, den ich oft verwenden. Fügen Sie dies in eine Konsolenanwendung ein, rufen Sie die Run-Methode auf und werfen Sie einige verwaltete Ausnahmen von jedem Prozess ab. Dadurch werden die Informationen und ihre Callstacks gedruckt.

HINWEIS: Sie benötigen das referenzierte NuGet-Paket, und verweisen Sie dann auf seine Assemblys, und dann wird dieser Code kompiliert.

class TraceLogMonitor 
{ 
    static TextWriter Out = AllSamples.Out; 

    public static void Run() 
    { 
     var monitoringTimeSec = 10; 
     TraceEventSession session = null; 

     Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs cancelArgs) => 
     { 
      if (session != null) 
       session.Dispose(); 
      cancelArgs.Cancel = true; 
     }; 

     var exceptionGeneationTask = Task.Factory.StartNew(delegate 
     { 
      Thread.Sleep(3000); 
      ThrowException(); 
     }); 

     Timer timer = null; 

     using (session = new TraceEventSession("TraceLogSession")) 
     { 
      Out.WriteLine("Enabling Image load, Process and Thread events. These are needed to look up native method names."); 
      session.EnableKernelProvider(

       KernelTraceEventParser.Keywords.ImageLoad | 
       KernelTraceEventParser.Keywords.Process, 
       KernelTraceEventParser.Keywords.None 
       ); 

      Out.WriteLine("Enabling CLR Exception and Load events (and stack for those events)"); 

      session.EnableProvider(
       ClrTraceEventParser.ProviderGuid, 
       TraceEventLevel.Informational, 
       (ulong)(ClrTraceEventParser.Keywords.Jit |    
       ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | 
       ClrTraceEventParser.Keywords.Loader |     
       ClrTraceEventParser.Keywords.Exception |    
       ClrTraceEventParser.Keywords.Stack));     

      Out.WriteLine("Enabling CLR Events to 'catch up' on JIT compiled code in running processes."); 
      session.EnableProvider(ClrRundownTraceEventParser.ProviderGuid, TraceEventLevel.Informational, 
       (ulong)(ClrTraceEventParser.Keywords.Jit |   
       ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | 
       ClrTraceEventParser.Keywords.Loader |    
       ClrTraceEventParser.Keywords.StartEnumeration));  

      TextWriter SymbolLookupMessages = new StringWriter(); 

      var symbolPath = new SymbolPath(SymbolPath.SymbolPathFromEnvironment).Add(SymbolPath.MicrosoftSymbolServerPath); 
      SymbolReader symbolReader = new SymbolReader(SymbolLookupMessages, symbolPath.ToString()); 

      Out.WriteLine("Open a real time TraceLog session (which understands how to decode stacks)."); 
      using (TraceLogEventSource traceLogSource = TraceLog.CreateFromTraceEventSession(session)) 
      { 
       Action<TraceEvent> PrintEvent = ((TraceEvent data) => Print(data, symbolReader)); 

       traceLogSource.Clr.ExceptionStart += PrintEvent; 
       traceLogSource.Clr.LoaderModuleLoad += PrintEvent; 

       traceLogSource.Kernel.PerfInfoSample += ((SampledProfileTraceData data) => Print(data, symbolReader)); 

       Out.WriteLine("Waiting {0} sec for Events. Run managed code to see data. ", monitoringTimeSec); 
       Out.WriteLine("Keep in mind there is a several second buffering delay"); 

       timer = new Timer(delegate(object state) 
       { 
        Out.WriteLine("Stopped Monitoring after {0} sec", monitoringTimeSec); 
        if (session != null) 
         session.Dispose(); 
        session = null; 
       }, null, monitoringTimeSec * 1000, Timeout.Infinite); 

       traceLogSource.Process(); 
      } 
     } 
     Out.WriteLine("Finished"); 
     if (timer != null) 
      timer.Dispose(); 
    } 

    static void Print(TraceEvent data, SymbolReader symbolReader) 
    { 
     if (data.Opcode == TraceEventOpcode.DataCollectionStart) 
      return; 

     if (data is ExceptionTraceData && ((ExceptionTraceData) data).ExceptionType.Length == 0) 
      return; 

     Out.WriteLine("EVENT: {0}", data.ToString()); 
     var callStack = data.CallStack(); 
     if (callStack != null) 
     { 
      ResolveNativeCode(callStack, symbolReader); 
      Out.WriteLine("CALLSTACK: {0}", callStack.ToString()); 
     } 
    } 

    static private void ResolveNativeCode(TraceCallStack callStack, SymbolReader symbolReader) 
    { 
     while (callStack != null) 
     { 
      var codeAddress = callStack.CodeAddress; 
      if (codeAddress.Method == null) 
      { 
       var moduleFile = codeAddress.ModuleFile; 
       if (moduleFile == null) 
        Trace.WriteLine(string.Format("Could not find module for Address 0x{0:x}", codeAddress.Address)); 
       else 
        codeAddress.CodeAddresses.LookupSymbolsForModule(symbolReader, moduleFile); 
      } 
      callStack = callStack.Caller; 
     } 
    } 

    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
    private static void ThrowException() 
    { 
     ThrowException1(); 
    } 

    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
    private static void ThrowException1() 
    { 
     Out.WriteLine("Causing an exception to happen so a CLR Exception Start event will be generated."); 
     try 
     { 
      throw new Exception("This is a test exception thrown to generate a CLR event"); 
     } 
     catch (Exception) { } 
    } 
}