[bcl] Updates referencesource to 4.7.1
[mono-project.git] / mcs / class / referencesource / System.ServiceModel.Internals / System / Runtime / ExceptionTrace.cs
blobc040bc4a632cd43cf27fbf59d73e7fec689d6b9d
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.Runtime
7 using System;
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;
18 class ExceptionTrace
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);
110 /// <summary>
111 /// Extracts the first inner exception of type <typeparamref name="TPreferredException"/>
112 /// from the <see cref="AggregateException"/> if one is present.
113 /// </summary>
114 /// <remarks>
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.
119 /// </remarks>
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
200 // [C#]
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);
224 break;
225 case TraceEventType.Warning:
226 if (TraceCore.HandledExceptionWarningIsEnabled(this.diagnosticTrace))
228 TraceCore.HandledExceptionWarning(this.diagnosticTrace, exception != null ? exception.ToString() : string.Empty, exception);
230 break;
231 case TraceEventType.Verbose:
232 if (TraceCore.HandledExceptionVerboseIsEnabled(this.diagnosticTrace))
234 TraceCore.HandledExceptionVerbose(this.diagnosticTrace, exception != null ? exception.ToString() : string.Empty, exception);
236 break;
237 default:
238 if (TraceCore.HandledExceptionIsEnabled(this.diagnosticTrace))
240 TraceCore.HandledException(this.diagnosticTrace, exception != null ? exception.ToString() : string.Empty, exception);
242 break;
246 public void TraceEtwException(Exception exception, TraceEventType eventType)
248 switch (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);
256 break;
257 case TraceEventType.Critical:
258 if (TraceCore.EtwUnhandledExceptionIsEnabled(this.diagnosticTrace))
260 TraceCore.EtwUnhandledException(this.diagnosticTrace, exception != null ? exception.ToString() : string.Empty, exception);
262 break;
263 default:
264 if (TraceCore.ThrowingEtwExceptionVerboseIsEnabled(this.diagnosticTrace))
266 TraceCore.ThrowingEtwExceptionVerbose(this.diagnosticTrace, this.eventSourceName, exception != null ? exception.ToString() : string.Empty, exception);
268 break;
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);
292 return 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)
300 #if DEBUG
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();
317 #endif
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)
337 if (logger != null)
341 string stackTrace = null;
344 stackTrace = new StackTrace().ToString();
346 catch (Exception exception)
348 stackTrace = exception.Message;
349 if (Fx.IsFatal(exception))
351 throw;
354 finally
356 logger.LogEvent(TraceEventType.Critical,
357 FailFastEventLogCategory,
358 (uint)System.Runtime.Diagnostics.EventLogEventId.FailFast,
359 message,
360 stackTrace);
363 catch (Exception ex)
365 logger.LogEvent(TraceEventType.Critical,
366 FailFastEventLogCategory,
367 (uint)System.Runtime.Diagnostics.EventLogEventId.FailFastException,
368 ex.ToString());
369 if (Fx.IsFatal(ex))
371 throw;