Dot-Net
使用 ETW 記錄異常的最佳方法是什麼?
是否有使用 ETW 記錄異常的標準方法?
據我所知,唯一的方法是記錄消息和可能的內部異常消息,因為異常類型沒有強類型參數。
使用額外的事件並在 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); } }使用級別和關鍵字來控制是否要一直記錄它。
所有 CLR 異常(第一次機會,以及可能最終導致您的應用程序崩潰的異常)都由 CLR 執行時提供程序在啟用時記錄到 ETW。
這是一個帶有呼叫堆棧的完全“結構化”事件(如果你想要的話)。實際上,您可以使用 TraceEvent NuGet 包(Install-Package 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) { } } }