diff --git a/src/Umbraco.Core/Configuration/CoreDebug.cs b/src/Umbraco.Core/Configuration/CoreDebug.cs new file mode 100644 index 0000000000..ff55be966b --- /dev/null +++ b/src/Umbraco.Core/Configuration/CoreDebug.cs @@ -0,0 +1,27 @@ +using System; + +namespace Umbraco.Core.Configuration +{ + internal static class CoreDebugExtensions + { + private static CoreDebug _coreDebug; + + public static CoreDebug CoreDebug(this UmbracoConfig config) + { + return _coreDebug ?? (_coreDebug = new CoreDebug()); + } + } + + internal class CoreDebug + { + public CoreDebug() + { + var appSettings = System.Configuration.ConfigurationManager.AppSettings; + DumpOnTimeoutThreadAbort = string.Equals("true", appSettings["Umbraco.CoreDebug.DumpOnTimeoutThreadAbort"], StringComparison.OrdinalIgnoreCase); + } + + // when true, the Logger creates a minidump of w3wp in ~/App_Data/MiniDump whenever it logs + // an error due to a ThreadAbortException that is due to a timeout. + public bool DumpOnTimeoutThreadAbort { get; private set; } + } +} diff --git a/src/Umbraco.Core/Logging/Logger.cs b/src/Umbraco.Core/Logging/Logger.cs index 66cad59733..30b1260305 100644 --- a/src/Umbraco.Core/Logging/Logger.cs +++ b/src/Umbraco.Core/Logging/Logger.cs @@ -7,6 +7,8 @@ using System.Threading; using System.Web; using log4net; using log4net.Config; +using Umbraco.Core.Configuration; +using Umbraco.Core.Diagnostics; namespace Umbraco.Core.Logging { @@ -57,21 +59,39 @@ namespace Umbraco.Core.Logging internal ILog LoggerFor(object getTypeFromInstance) { if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance"); - + return LogManager.GetLogger(getTypeFromInstance.GetType()); } - + public void Error(Type callingType, string message, Exception exception) { var logger = LogManager.GetLogger(callingType); if (logger == null) return; + var dump = false; + if (IsTimeoutThreadAbortException(exception)) { message += "\r\nThe thread has been aborted, because the request has timed out."; + dump = UmbracoConfig.For.CoreDebug().DumpOnTimeoutThreadAbort; } - logger.Error(message, exception); + if (dump) + { + try + { + var dumped = MiniDump.Dump(withException: true); + message += dumped + ? "\r\nA minidump was created in App_Data/MiniDump" + : "\r\nFailed to create a minidump"; + } + catch (Exception e) + { + message += string.Format("\r\nFailed to create a minidump ({0}: {1})", e.GetType().FullName, e.Message); + } + } + + logger.Error(message, exception); } private static bool IsTimeoutThreadAbortException(Exception exception) @@ -105,7 +125,7 @@ namespace Umbraco.Core.Logging if (showHttpTrace && HttpContext.Current != null) { HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray())); - } + } var logger = LogManager.GetLogger(callingType); if (logger == null || logger.IsWarnEnabled == false) return; @@ -122,7 +142,7 @@ namespace Umbraco.Core.Logging var logger = LogManager.GetLogger(callingType); if (logger == null || logger.IsWarnEnabled == false) return; var executedParams = formatItems.Select(x => x.Invoke()).ToArray(); - logger.WarnFormat((message) + ". Exception: " + e, executedParams); + logger.WarnFormat((message) + ". Exception: " + e, executedParams); } /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index e03dabfa5f..b22301bc8e 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -180,6 +180,7 @@ + @@ -300,6 +301,7 @@ +