Wszystkie wyjątki CLR (pierwsza szansa i te, które mogą zakończyć się zrywaniem aplikacji) są rejestrowane w ETW przez dostawcę środowiska wykonawczego CLR, gdy są włączone.
To jest zdarzenie "w pełni zorganizowane" Z WYSZUKIWANIEM (jeśli chcesz). W rzeczywistości, można napisać aplikację monitoringu przy użyciu pakietu TraceEvent Nuget (Instaluj-Pakiet Microsoft.Diagnostics.Tracing.TraceEvent)
jestem wklejając kod monitoringu często używam. Umieść to w aplikacji konsoli, wywołaj metodę Run i wyrzuć niektóre zarządzane wyjątki z dowolnego procesu, wydrukuje informacje i ich stacje.
UWAGA: Musisz odwołać się do pakietu NuGet, a następnie odwołać się do jego złożeń, a następnie ten kod zostanie skompilowany.
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) { }
}
}
Ponieważ nie można używać silnie typ wyjątków wobec EventSource byłoby najlepiej po prostu nazywając go tak: EventSource.Log.Failure (MyException.ToString())? – jaffa
to byłoby w porządku. – magicandre1981