使用ETW记录异常的最佳方式是什么?

问题描述:

有没有使用ETW记录异常的标准方法?使用ETW记录异常的最佳方式是什么?

据我所见,唯一的方法是记录消息,并且可能会记录内部异常消息,因为没有强类型的Exception类型参数。

使用一个额外的事件和火灾catch块这一事件,并与级别和关键字传递异常消息作为参数传递给事件

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

播放控制,如果你想记录这一切的时间与否。

+0

因为你不能对EventSource使用强类型异常,所以我最好只是这样调用它:EventSource.Log.Failure(MyException.ToString())? – jaffa

+0

这可以。 – magicandre1981

ETW不是.NET特有的,因此不会有任何强类型的.NET特定API来记录.net异常。你会改为创建自己的强类型API。这是语义记录和语义记录应用程序块的思想。

+0

因此在一天结束时为了使用ETW只能使用原始数据类型,字符串和数字(​​以字符串的形式)?纯粹将Exception序列化为一个足够好的字符串?或者是否有非模式的应用程序追踪异常? – BozoJoe

+1

ETW是一种二进制有效载荷,支持您定义的结构。 http://msdn.microsoft.com/en-us/library/windows/desktop/aa382774(v=vs.85).aspx 只是,当你走这条路线,你必须写一个自定义的解码器。在.NET的情况下,.NET团队已经提供了一个明确的定义。 但是,像本机代码中的许多事情一样,有多种方法可以实现。 C++异常? SEH例外?等等。例外的最感兴趣的部分是由ETW标准化的callstack(以及它的EIPs,以获得行号),以及它的步行者。除此之外的任何信息都是您的电话。 – mjsabby

CLR运行时提供程序在启用时会记录所有CLR异常(第一次机会以及可能最终导致应用程序中断的异常)。

这是一个完全“结构化”的事件与调用堆栈(如果你想要他们)。事实上,你可以写使用TraceEvent NuGet包监视应用程序(安装,包装Microsoft.Diagnostics.Tracing.TraceEvent

我贴上监管码我经常使用。把它放在一个控制台应用程序中,调用Run方法,并从任何进程中抛出一些托管异常,它将打印信息和它们的调用堆栈。

注意:您需要引用的NuGet包,然后引用其程序集,然后编译此代码。

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) { } 
    } 
}