1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System
.Runtime
8 using System
.Collections
.ObjectModel
;
9 using System
.Diagnostics
;
10 using System
.Globalization
;
11 using System
.Reflection
;
12 using System
.Runtime
.CompilerServices
;
13 using System
.Runtime
.Diagnostics
;
14 using System
.Runtime
.Interop
;
15 using System
.Runtime
.Versioning
;
16 using System
.Security
;
20 const ushort FailFastEventLogCategory
= 6;
21 string eventSourceName
;
22 readonly EtwDiagnosticTrace diagnosticTrace
;
24 public ExceptionTrace(string eventSourceName
, EtwDiagnosticTrace diagnosticTrace
)
26 Fx
.Assert(diagnosticTrace
!= null, "'diagnosticTrace' MUST NOT be NULL.");
28 this.eventSourceName
= eventSourceName
;
29 this.diagnosticTrace
= diagnosticTrace
;
32 public void AsInformation(Exception exception
)
34 //Traces an informational trace message
35 TraceCore
.HandledException(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
38 public void AsWarning(Exception exception
)
40 //Traces a warning trace message
41 TraceCore
.HandledExceptionWarning(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
44 public Exception
AsError(Exception exception
)
46 // AggregateExceptions are automatically unwrapped.
47 AggregateException aggregateException
= exception
as AggregateException
;
48 if (aggregateException
!= null)
50 return AsError
<Exception
>(aggregateException
);
53 // TargetInvocationExceptions are automatically unwrapped.
54 TargetInvocationException targetInvocationException
= exception
as TargetInvocationException
;
55 if (targetInvocationException
!= null && targetInvocationException
.InnerException
!= null)
57 return AsError(targetInvocationException
.InnerException
);
60 return TraceException
<Exception
>(exception
);
63 public Exception
AsError(Exception exception
, string eventSource
)
65 // AggregateExceptions are automatically unwrapped.
66 AggregateException aggregateException
= exception
as AggregateException
;
67 if (aggregateException
!= null)
69 return AsError
<Exception
>(aggregateException
, eventSource
);
72 // TargetInvocationExceptions are automatically unwrapped.
73 TargetInvocationException targetInvocationException
= exception
as TargetInvocationException
;
74 if (targetInvocationException
!= null && targetInvocationException
.InnerException
!= null)
76 return AsError(targetInvocationException
.InnerException
, eventSource
);
79 return TraceException
<Exception
>(exception
, eventSource
);
82 public Exception
AsError(TargetInvocationException targetInvocationException
, string eventSource
)
84 Fx
.Assert(targetInvocationException
!= null, "targetInvocationException cannot be null.");
86 // If targetInvocationException contains any fatal exceptions, return it directly
87 // without tracing it or any inner exceptions.
88 if (Fx
.IsFatal(targetInvocationException
))
90 return targetInvocationException
;
93 // A non-null inner exception could require further unwrapping in AsError.
94 Exception innerException
= targetInvocationException
.InnerException
;
95 if (innerException
!= null)
97 return AsError(innerException
, eventSource
);
100 // A null inner exception is unlikely but possible.
101 // In this case, trace and return the targetInvocationException itself.
102 return TraceException
<Exception
>(targetInvocationException
, eventSource
);
105 public Exception AsError
<TPreferredException
>(AggregateException aggregateException
)
107 return AsError
<TPreferredException
>(aggregateException
, this.eventSourceName
);
111 /// Extracts the first inner exception of type <typeparamref name="TPreferredException"/>
112 /// from the <see cref="AggregateException"/> if one is present.
115 /// If no <typeparamref name="TPreferredException"/> inner exception is present, this
116 /// method returns the first inner exception. All inner exceptions will be traced,
117 /// including the one returned. The containing <paramref name="aggregateException"/>
118 /// will not be traced unless there are no inner exceptions.
120 /// <typeparam name="TPreferredException">The preferred type of inner exception to extract.
121 /// Use <c>typeof(Exception)</c> to extract the first exception regardless of type.</typeparam>
122 /// <param name="aggregateException">The <see cref="AggregateException"/> to examine.</param>
123 /// <param name="eventSource">The event source to trace.</param>
124 /// <returns>The extracted exception. It will not be <c>null</c>
125 /// but it may not be of type <typeparamref name="TPreferredException"/>.</returns>
126 public Exception AsError
<TPreferredException
>(AggregateException aggregateException
, string eventSource
)
128 Fx
.Assert(aggregateException
!= null, "aggregateException cannot be null.");
130 // If aggregateException contains any fatal exceptions, return it directly
131 // without tracing it or any inner exceptions.
132 if (Fx
.IsFatal(aggregateException
))
134 return aggregateException
;
137 // Collapse possibly nested graph into a flat list.
138 // Empty inner exception list is unlikely but possible via public api.
139 ReadOnlyCollection
<Exception
> innerExceptions
= aggregateException
.Flatten().InnerExceptions
;
140 if (innerExceptions
.Count
== 0)
142 return TraceException(aggregateException
, eventSource
);
145 // Find the first inner exception, giving precedence to TPreferredException
146 Exception favoredException
= null;
147 foreach (Exception nextInnerException
in innerExceptions
)
149 // AggregateException may wrap TargetInvocationException, so unwrap those as well
150 TargetInvocationException targetInvocationException
= nextInnerException
as TargetInvocationException
;
152 Exception innerException
= (targetInvocationException
!= null && targetInvocationException
.InnerException
!= null)
153 ? targetInvocationException
.InnerException
154 : nextInnerException
;
156 if (innerException
is TPreferredException
&& favoredException
== null)
158 favoredException
= innerException
;
161 // All inner exceptions are traced
162 TraceException
<Exception
>(innerException
, eventSource
);
165 if (favoredException
== null)
167 Fx
.Assert(innerExceptions
.Count
> 0, "InnerException.Count is known to be > 0 here.");
168 favoredException
= innerExceptions
[0];
171 return favoredException
;
174 public ArgumentException
Argument(string paramName
, string message
)
176 return TraceException
<ArgumentException
>(new ArgumentException(message
, paramName
));
179 public ArgumentNullException
ArgumentNull(string paramName
)
181 return TraceException
<ArgumentNullException
>(new ArgumentNullException(paramName
));
184 public ArgumentNullException
ArgumentNull(string paramName
, string message
)
186 return TraceException
<ArgumentNullException
>(new ArgumentNullException(paramName
, message
));
189 public ArgumentException
ArgumentNullOrEmpty(string paramName
)
191 return this.Argument(paramName
, InternalSR
.ArgumentNullOrEmpty(paramName
));
194 public ArgumentOutOfRangeException
ArgumentOutOfRange(string paramName
, object actualValue
, string message
)
196 return TraceException
<ArgumentOutOfRangeException
>(new ArgumentOutOfRangeException(paramName
, actualValue
, message
));
199 // When throwing ObjectDisposedException, it is highly recommended that you use this ctor
201 // public ObjectDisposedException(string objectName, string message);
202 // And provide null for objectName but meaningful and relevant message for message.
203 // It is recommended because end user really does not care or can do anything on the disposed object, commonly an internal or private object.
204 public ObjectDisposedException
ObjectDisposed(string message
)
206 // pass in null, not disposedObject.GetType().FullName as per the above guideline
207 return TraceException
<ObjectDisposedException
>(new ObjectDisposedException(null, message
));
210 public void TraceUnhandledException(Exception exception
)
212 TraceCore
.UnhandledException(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
215 public void TraceHandledException(Exception exception
, TraceEventType traceEventType
)
217 switch (traceEventType
)
219 case TraceEventType
.Error
:
220 if (TraceCore
.HandledExceptionErrorIsEnabled(this.diagnosticTrace
))
222 TraceCore
.HandledExceptionError(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
225 case TraceEventType
.Warning
:
226 if (TraceCore
.HandledExceptionWarningIsEnabled(this.diagnosticTrace
))
228 TraceCore
.HandledExceptionWarning(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
231 case TraceEventType
.Verbose
:
232 if (TraceCore
.HandledExceptionVerboseIsEnabled(this.diagnosticTrace
))
234 TraceCore
.HandledExceptionVerbose(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
238 if (TraceCore
.HandledExceptionIsEnabled(this.diagnosticTrace
))
240 TraceCore
.HandledException(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
246 public void TraceEtwException(Exception exception
, TraceEventType eventType
)
250 case TraceEventType
.Error
:
251 case TraceEventType
.Warning
:
252 if (TraceCore
.ThrowingEtwExceptionIsEnabled(this.diagnosticTrace
))
254 TraceCore
.ThrowingEtwException(this.diagnosticTrace
, this.eventSourceName
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
257 case TraceEventType
.Critical
:
258 if (TraceCore
.EtwUnhandledExceptionIsEnabled(this.diagnosticTrace
))
260 TraceCore
.EtwUnhandledException(this.diagnosticTrace
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
264 if (TraceCore
.ThrowingEtwExceptionVerboseIsEnabled(this.diagnosticTrace
))
266 TraceCore
.ThrowingEtwExceptionVerbose(this.diagnosticTrace
, this.eventSourceName
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
272 TException TraceException
<TException
>(TException exception
)
273 where TException
: Exception
275 return TraceException
<TException
>(exception
, this.eventSourceName
);
278 [ResourceConsumption(ResourceScope
.Process
)]
279 [Fx
.Tag
.SecurityNote(Critical
= "Calls 'System.Runtime.Interop.UnsafeNativeMethods.IsDebuggerPresent()' which is a P/Invoke method",
280 Safe
= "Does not leak any resource, needed for debugging")]
281 [SecuritySafeCritical
]
282 TException TraceException
<TException
>(TException exception
, string eventSource
)
283 where TException
: Exception
285 if (TraceCore
.ThrowingExceptionIsEnabled(this.diagnosticTrace
))
287 TraceCore
.ThrowingException(this.diagnosticTrace
, eventSource
, exception
!= null ? exception
.ToString() : string.Empty
, exception
);
290 BreakOnException(exception
);
295 [Fx
.Tag
.SecurityNote(Critical
= "Calls into critical method UnsafeNativeMethods.IsDebuggerPresent and UnsafeNativeMethods.DebugBreak",
296 Safe
= "Safe because it's a no-op in retail builds.")]
297 [SecuritySafeCritical
]
298 void BreakOnException(Exception exception
)
301 if (Fx
.BreakOnExceptionTypes
!= null)
303 foreach (Type breakType
in Fx
.BreakOnExceptionTypes
)
305 if (breakType
.IsAssignableFrom(exception
.GetType()))
307 // This is intended to "crash" the process so that a debugger can be attached. If a managed
308 // debugger is already attached, it will already be able to hook these exceptions. We don't
309 // want to simulate an unmanaged crash (DebugBreak) in that case.
310 if (!Debugger
.IsAttached
&& !UnsafeNativeMethods
.IsDebuggerPresent())
312 UnsafeNativeMethods
.DebugBreak();
320 [MethodImpl(MethodImplOptions
.NoInlining
)]
321 internal void TraceFailFast(string message
)
323 EventLogger logger
= null;
324 #pragma warning disable 618
325 logger
= new EventLogger(this.eventSourceName
, this.diagnosticTrace
);
326 #pragma warning restore 618
327 TraceFailFast(message
, logger
);
330 // Generate an event Log entry for failfast purposes
331 // To force a Watson on a dev machine, do the following:
332 // 1. Set \HKLM\SOFTWARE\Microsoft\PCHealth\ErrorReporting ForceQueueMode = 0
333 // 2. In the command environment, set COMPLUS_DbgJitDebugLaunchSetting=0
334 [MethodImpl(MethodImplOptions
.NoInlining
)]
335 internal void TraceFailFast(string message
, EventLogger logger
)
341 string stackTrace
= null;
344 stackTrace
= new StackTrace().ToString();
346 catch (Exception exception
)
348 stackTrace
= exception
.Message
;
349 if (Fx
.IsFatal(exception
))
356 logger
.LogEvent(TraceEventType
.Critical
,
357 FailFastEventLogCategory
,
358 (uint)System
.Runtime
.Diagnostics
.EventLogEventId
.FailFast
,
365 logger
.LogEvent(TraceEventType
.Critical
,
366 FailFastEventLogCategory
,
367 (uint)System
.Runtime
.Diagnostics
.EventLogEventId
.FailFastException
,