diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index a763b22e36..a9a468319e 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -58,6 +58,7 @@ namespace Umbraco.Core.Composing // resets *everything* that is 'current' internal static void Reset() { + _container?.Dispose(); _container = null; _shortStringHelper = null; diff --git a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs b/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs index 1aa5594fad..d1bde55306 100644 --- a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs +++ b/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs @@ -7,6 +7,9 @@ namespace Umbraco.Core.Logging /// public class DebugDiagnosticsLogger : ILogger { + public bool IsEnabled(Type reporting, LogLevel level) + => true; + /// public void Fatal(Type reporting, Exception exception, string message) { @@ -26,15 +29,15 @@ namespace Umbraco.Core.Logging } /// - public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] args) + public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, args) + Environment.NewLine + exception, reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName); } /// - public void Fatal(Type reporting, string messageTemplate, params object[] args) + public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(messageTemplate, args); + System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues); } /// @@ -56,27 +59,27 @@ namespace Umbraco.Core.Logging } /// - public void Error(Type reporting, Exception exception, string messageTemplate, params object[] args) + public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, args) + Environment.NewLine + exception, reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName); } /// - public void Error(Type reporting, string messageTemplate, params object[] args) + public void Error(Type reporting, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(messageTemplate, args); + System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues); } /// - public void Warn(Type reporting, string format) + public void Warn(Type reporting, string message) { - System.Diagnostics.Debug.WriteLine(format, reporting.FullName); + System.Diagnostics.Debug.WriteLine(message, reporting.FullName); } - + /// - public void Warn(Type reporting, string format, params object[] args) + public void Warn(Type reporting, string message, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(format, args), reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message, propertyValues), reporting.FullName); } /// @@ -86,9 +89,9 @@ namespace Umbraco.Core.Logging } /// - public void Warn(Type reporting, Exception exception, string format, params object[] args) + public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(format + Environment.NewLine + exception, args), reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message + Environment.NewLine + exception, propertyValues), reporting.FullName); } /// @@ -98,9 +101,9 @@ namespace Umbraco.Core.Logging } /// - public void Info(Type reporting, string format, params object[] args) + public void Info(Type reporting, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(format, args), reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); } /// @@ -110,9 +113,9 @@ namespace Umbraco.Core.Logging } /// - public void Debug(Type reporting, string format, params object[] args) + public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(format, args), reporting.FullName); + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); } /// @@ -122,9 +125,9 @@ namespace Umbraco.Core.Logging } /// - public void Verbose(Type reporting, string format, params object[] args) + public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) { - System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(format, args), reporting.FullName); - } + System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); + } } } diff --git a/src/Umbraco.Core/Logging/DisposableTimer.cs b/src/Umbraco.Core/Logging/DisposableTimer.cs index 869ca2cd44..db530e5339 100644 --- a/src/Umbraco.Core/Logging/DisposableTimer.cs +++ b/src/Umbraco.Core/Logging/DisposableTimer.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Logging public class DisposableTimer : DisposableObjectSlim { private readonly ILogger _logger; - private readonly LogType? _logType; + private readonly LogLevel _level; private readonly Type _loggerType; private readonly int _thresholdMilliseconds; private readonly IDisposable _profilerStep; @@ -19,22 +19,14 @@ namespace Umbraco.Core.Logging private bool _failed; private readonly string _timingId; - internal enum LogType - { - Debug, Info - } - // internal - created by profiling logger - internal DisposableTimer(ILogger logger, LogType logType, IProfiler profiler, Type loggerType, + internal DisposableTimer(ILogger logger, LogLevel level, IProfiler profiler, Type loggerType, string startMessage, string endMessage, string failMessage = null, int thresholdMilliseconds = 0) { - if (logger == null) throw new ArgumentNullException(nameof(logger)); - if (loggerType == null) throw new ArgumentNullException(nameof(loggerType)); - - _logger = logger; - _logType = logType; - _loggerType = loggerType; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _level = level; + _loggerType = loggerType ?? throw new ArgumentNullException(nameof(loggerType)); _endMessage = endMessage; _failMessage = failMessage; _thresholdMilliseconds = thresholdMilliseconds < 0 ? 0 : thresholdMilliseconds; @@ -42,16 +34,16 @@ namespace Umbraco.Core.Logging if (thresholdMilliseconds == 0) { - switch (logType) + switch (_level) { - case LogType.Debug: + case LogLevel.Debug: logger.Debug(loggerType, "[Timing {TimingId}] {StartMessage}", _timingId, startMessage); break; - case LogType.Info: + case LogLevel.Information: logger.Info(loggerType, "[Timing {TimingId}] {StartMessage}", _timingId, startMessage); break; default: - throw new ArgumentOutOfRangeException(nameof(logType)); + throw new ArgumentOutOfRangeException(nameof(level)); } } @@ -87,19 +79,19 @@ namespace Umbraco.Core.Logging _profilerStep?.Dispose(); if ((Stopwatch.ElapsedMilliseconds >= _thresholdMilliseconds || _failed) - && _logType.HasValue && _loggerType != null && _logger != null + && _loggerType != null && _logger != null && (_endMessage.IsNullOrWhiteSpace() == false || _failed)) { if (_failed) { _logger.Error(_loggerType, _failException, "[Timing {TimingId}] {FailMessage} ({TimingDuration}ms)", _timingId, _failMessage, Stopwatch.ElapsedMilliseconds); } - else switch (_logType) + else switch (_level) { - case LogType.Debug: + case LogLevel.Debug: _logger.Debug(_loggerType, "[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)", _timingId, _endMessage, Stopwatch.ElapsedMilliseconds); break; - case LogType.Info: + case LogLevel.Information: _logger.Info(_loggerType, "[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)", _timingId, _endMessage, Stopwatch.ElapsedMilliseconds); break; // filtered in the ctor diff --git a/src/Umbraco.Core/Logging/ILogger.cs b/src/Umbraco.Core/Logging/ILogger.cs index 2162b10bfe..4f49d0b3b4 100644 --- a/src/Umbraco.Core/Logging/ILogger.cs +++ b/src/Umbraco.Core/Logging/ILogger.cs @@ -14,6 +14,13 @@ namespace Umbraco.Core.Logging /// public interface ILogger { + /// + /// Determines if logging is enabled at a specified level, for a reporting type. + /// + /// The reporting type. + /// The level. + bool IsEnabled(Type reporting, LogLevel level); + /// /// Logs a fatal message with an exception. /// diff --git a/src/Umbraco.Core/Logging/LogLevel.cs b/src/Umbraco.Core/Logging/LogLevel.cs new file mode 100644 index 0000000000..f1b65499d6 --- /dev/null +++ b/src/Umbraco.Core/Logging/LogLevel.cs @@ -0,0 +1,15 @@ +namespace Umbraco.Core.Logging +{ + /// + /// Specifies the level of a log event. + /// + public enum LogLevel + { + Verbose, + Debug, + Information, + Warning, + Error, + Fatal + } +} diff --git a/src/Umbraco.Core/Logging/LoggerExtensions.cs b/src/Umbraco.Core/Logging/LoggerExtensions.cs index c29bcef4f7..3b105ed888 100644 --- a/src/Umbraco.Core/Logging/LoggerExtensions.cs +++ b/src/Umbraco.Core/Logging/LoggerExtensions.cs @@ -8,63 +8,62 @@ namespace Umbraco.Core.Logging public static class LoggerExtensions { /// - /// Logs an error message + /// Determines if logging is enabled at a specified level, for a reporting type. + /// + /// The reporting type. + /// The logger. + /// The level. + public static bool IsEnabled(this ILogger logger, LogLevel level) + => logger.IsEnabled(typeof(T), level); + + /// + /// Logs an error message with an exception. /// /// The reporting type. /// The logger. /// A message. /// An exception. public static void Error(this ILogger logger, Exception exception, string message) - { - logger.Error(typeof(T), exception, message); - } + => logger.Error(typeof(T), exception, message); /// - /// Logs an error message with a structured message template + /// Logs an error message with an exception. /// - /// The reporting type + /// The reporting type. /// The logger. - /// A structured message template - /// An exception - /// Message property values + /// An exception. + /// A message template. + /// Property values. public static void Error(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - { - logger.Error(typeof(T), exception, messageTemplate, propertyValues); - } + => logger.Error(typeof(T), exception, messageTemplate, propertyValues); /// - /// Logs an error message NOTE: This will log an empty message string + /// Logs an error exception. /// - /// The reporting type + /// The reporting type. /// The logger. - /// An exception + /// An exception. public static void Error(this ILogger logger, Exception exception) - { - logger.Error(typeof(T), exception); - } + => logger.Error(typeof(T), exception); /// - /// Logs an error message WITHOUT EX + /// Logs an error message. /// - /// - /// - /// - public static void Error(this ILogger logger, string message) - { - logger.Error(typeof(T), message); - } - - /// - /// Logs an error message - using a structured log message - /// - /// The reporting type + /// The reporting type. /// The logger. - /// A structured message template - /// Message property values + /// A message. + public static void Error(this ILogger logger, string message) + => logger.Error(typeof(T), message); + + /// + /// Logs an error message. + /// + /// The reporting type. + /// The logger. + /// A message template. + /// Property values. public static void Error(this ILogger logger, string messageTemplate, params object[] propertyValues) - { - logger.Error(typeof(T), messageTemplate, propertyValues); - } + => logger.Error(typeof(T), messageTemplate, propertyValues); /// /// Logs a warning message. @@ -73,46 +72,38 @@ namespace Umbraco.Core.Logging /// The logger. /// A message. public static void Warn(this ILogger logger, string message) - { - logger.Warn(typeof(T), message); - } + => logger.Warn(typeof(T), message); /// - /// Logs a warning message with a structured message template + /// Logs a warning message. /// - /// The reporting type + /// The reporting type. /// The logger. - /// A structured message template - /// Message property values + /// A message template. + /// Property values. public static void Warn(this ILogger logger, string messageTemplate, params object[] propertyValues) - { - logger.Warn(typeof(T), messageTemplate, propertyValues); - } + => logger.Warn(typeof(T), messageTemplate, propertyValues); /// - /// Logs a formatted warning message with an exception. + /// Logs a warning message with an exception. /// /// The reporting type. /// The logger. /// An exception. /// A message. public static void Warn(this ILogger logger, Exception exception, string message) - { - logger.Warn(typeof(T), exception, message); - } + => logger.Warn(typeof(T), exception, message); /// - /// Logs a warning message with an exception with a structured message template + /// Logs a warning message with an exception. /// - /// The reporting type + /// The reporting type. /// The logger. - /// An exception - /// A structured message template - /// Message property values + /// An exception. + /// A message template. + /// Property values. public static void Warn(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - { - logger.Warn(typeof(T), exception, messageTemplate, propertyValues); - } + => logger.Warn(typeof(T), exception, messageTemplate, propertyValues); /// /// Logs an information message. @@ -121,21 +112,17 @@ namespace Umbraco.Core.Logging /// The logger. /// A message. public static void Info(this ILogger logger, string message) - { - logger.Info(typeof(T), message); - } + => logger.Info(typeof(T), message); /// - /// Logs a information message with a structured message template + /// Logs a information message. /// /// The reporting type /// The logger. - /// A structured message template - /// Message property values + /// A message template. + /// Property values. public static void Info(this ILogger logger, string messageTemplate, params object[] propertyValues) - { - logger.Info(typeof(T), messageTemplate, propertyValues); - } + => logger.Info(typeof(T), messageTemplate, propertyValues); /// /// Logs a debugging message. @@ -144,21 +131,17 @@ namespace Umbraco.Core.Logging /// The logger. /// A message. public static void Debug(this ILogger logger, string message) - { - logger.Debug(typeof(T), message); - } + => logger.Debug(typeof(T), message); /// - /// Logs a debugging message with a structured message template + /// Logs a debugging message. /// /// The reporting type /// The logger. - /// A structured message template - /// Message property values + /// A message template. + /// Property values. public static void Debug(this ILogger logger, string messageTemplate, params object[] propertyValues) - { - logger.Debug(typeof(T), messageTemplate, propertyValues); - } + => logger.Debug(typeof(T), messageTemplate, propertyValues); /// /// Logs a verbose message. @@ -167,22 +150,17 @@ namespace Umbraco.Core.Logging /// The logger. /// A message. public static void Verbose(this ILogger logger, string message) - { - logger.Verbose(typeof(T), message); - } + => logger.Verbose(typeof(T), message); /// - /// Logs a Verbose message with a structured message template + /// Logs a verbose message. /// - /// The reporting type + /// The reporting type. /// The logger. - /// A structured message template - /// Message property values + /// A message template. + /// Property values. public static void Verbose(this ILogger logger, string messageTemplate, params object[] propertyValues) - { - logger.Verbose(typeof(T), messageTemplate, propertyValues); - } - + => logger.Verbose(typeof(T), messageTemplate, propertyValues); /// /// Logs a fatal message. @@ -192,23 +170,17 @@ namespace Umbraco.Core.Logging /// An exception. /// A message. public static void Fatal(this ILogger logger, Exception exception, string message) - { - logger.Fatal(typeof(T), exception, message); - } - + => logger.Fatal(typeof(T), exception, message); /// - /// Logs a fatal message with a structured message template + /// Logs a fatal message. /// /// The reporting type. /// The logger. /// An exception. - /// A structured message template - /// Message property values + /// A message template. + /// Property values. public static void Fatal(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - { - logger.Fatal(typeof(T), exception, messageTemplate, propertyValues); - } - + => logger.Fatal(typeof(T), exception, messageTemplate, propertyValues); } } diff --git a/src/Umbraco.Core/Logging/MessageTemplates.cs b/src/Umbraco.Core/Logging/MessageTemplates.cs index 04e802a61d..194d47c339 100644 --- a/src/Umbraco.Core/Logging/MessageTemplates.cs +++ b/src/Umbraco.Core/Logging/MessageTemplates.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using Serilog; -using Umbraco.Core.Logging.SerilogExtensions; namespace Umbraco.Core.Logging { @@ -16,19 +15,19 @@ namespace Umbraco.Core.Logging // but it only has a pre-release NuGet package. So, we've got to use Serilog's code, which // means we cannot get rid of Serilog entirely. We may want to revisit this at some point. - private static readonly Lazy MinimalLogger = new Lazy(() => new LoggerConfiguration().CreateLogger()); + private static readonly Lazy MinimalLogger = new Lazy(() => new LoggerConfiguration().CreateLogger()); public static string Render(string messageTemplate, params object[] args) { // by default, unless initialized otherwise, Log.Logger is SilentLogger which cannot bind message // templates. Log.Logger is set to a true Logger when initializing Umbraco's logger, but in case // that has not been done already - use a temp minimal logger (eg for tests). - var logger = Log.Logger as Serilog.Core.Logger ?? MinimalLogger.Value; + var logger = Log.Logger as global::Serilog.Core.Logger ?? MinimalLogger.Value; var bound = logger.BindMessageTemplate(messageTemplate, args, out var parsedTemplate, out var boundProperties); if (!bound) - throw new FormatException($"Could not format message \"{messageTemplate}\" with {args.Length} args."); + throw new FormatException($"Could not format message \"{messageTemplate}\" with {args.Length} args."); return parsedTemplate.Render(boundProperties.ToDictionary(x => x.Name, x => x.Value)); } diff --git a/src/Umbraco.Core/Logging/ProfilingLogger.cs b/src/Umbraco.Core/Logging/ProfilingLogger.cs index 28d2494b0d..80560e923a 100644 --- a/src/Umbraco.Core/Logging/ProfilingLogger.cs +++ b/src/Umbraco.Core/Logging/ProfilingLogger.cs @@ -13,10 +13,8 @@ namespace Umbraco.Core.Logging public ProfilingLogger(ILogger logger, IProfiler profiler) { - if (logger == null) throw new ArgumentNullException(nameof(logger)); - if (profiler == null) throw new ArgumentNullException(nameof(profiler)); - Logger = logger; - Profiler = profiler; + Logger = logger ?? throw new ArgumentNullException(nameof(logger)); + Profiler = profiler ?? throw new ArgumentNullException(nameof(profiler)); } public DisposableTimer TraceDuration(string startMessage) @@ -26,27 +24,33 @@ namespace Umbraco.Core.Logging public DisposableTimer TraceDuration(string startMessage, string completeMessage, string failMessage = null) { - return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, completeMessage, failMessage); + return new DisposableTimer(Logger, LogLevel.Information, Profiler, typeof(T), startMessage, completeMessage, failMessage); } public DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null) { - return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, loggerType, startMessage, completeMessage, failMessage); + return new DisposableTimer(Logger, LogLevel.Information, Profiler, loggerType, startMessage, completeMessage, failMessage); } public DisposableTimer DebugDuration(string startMessage) { - return DebugDuration(startMessage, "Completed."); + return Logger.IsEnabled(LogLevel.Debug) + ? DebugDuration(startMessage, "Completed.") + : null; } public DisposableTimer DebugDuration(string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0) { - return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, completeMessage, failMessage, thresholdMilliseconds); + return Logger.IsEnabled(LogLevel.Debug) + ? new DisposableTimer(Logger, LogLevel.Debug, Profiler, typeof(T), startMessage, completeMessage, failMessage, thresholdMilliseconds) + : null; } public DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0) { - return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds); + return Logger.IsEnabled(loggerType, LogLevel.Debug) + ? new DisposableTimer(Logger, LogLevel.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds) + : null; } } } diff --git a/src/Umbraco.Core/Logging/SerilogExtensions/Log4NetLevelMapperEnricher.cs b/src/Umbraco.Core/Logging/Serilog/Log4NetLevelMapperEnricher.cs similarity index 96% rename from src/Umbraco.Core/Logging/SerilogExtensions/Log4NetLevelMapperEnricher.cs rename to src/Umbraco.Core/Logging/Serilog/Log4NetLevelMapperEnricher.cs index 681f7b4936..1424fa0b55 100644 --- a/src/Umbraco.Core/Logging/SerilogExtensions/Log4NetLevelMapperEnricher.cs +++ b/src/Umbraco.Core/Logging/Serilog/Log4NetLevelMapperEnricher.cs @@ -1,7 +1,7 @@ using Serilog.Core; using Serilog.Events; -namespace Umbraco.Core.Logging.SerilogExtensions +namespace Umbraco.Core.Logging.Serilog { /// /// This is used to create a new property in Logs called 'Log4NetLevel' diff --git a/src/Umbraco.Core/Logging/SerilogExtensions/LoggerConfigExtensions.cs b/src/Umbraco.Core/Logging/Serilog/LoggerConfigExtensions.cs similarity index 97% rename from src/Umbraco.Core/Logging/SerilogExtensions/LoggerConfigExtensions.cs rename to src/Umbraco.Core/Logging/Serilog/LoggerConfigExtensions.cs index 150fb0395c..8861c808df 100644 --- a/src/Umbraco.Core/Logging/SerilogExtensions/LoggerConfigExtensions.cs +++ b/src/Umbraco.Core/Logging/Serilog/LoggerConfigExtensions.cs @@ -4,7 +4,7 @@ using Serilog; using Serilog.Events; using Serilog.Formatting.Compact; -namespace Umbraco.Core.Logging.SerilogExtensions +namespace Umbraco.Core.Logging.Serilog { public static class LoggerConfigExtensions { @@ -16,7 +16,7 @@ namespace Umbraco.Core.Logging.SerilogExtensions /// A Serilog LoggerConfiguration public static LoggerConfiguration MinimalConfiguration(this LoggerConfiguration logConfig) { - Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg)); + global::Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg)); //Set this environment variable - so that it can be used in external config file //add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" /> diff --git a/src/Umbraco.Core/Logging/Logger.cs b/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs similarity index 57% rename from src/Umbraco.Core/Logging/Logger.cs rename to src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs index 0a20022e93..6d3b2b28b3 100644 --- a/src/Umbraco.Core/Logging/Logger.cs +++ b/src/Umbraco.Core/Logging/Serilog/SerilogLogger.cs @@ -2,41 +2,40 @@ using System.IO; using System.Reflection; using System.Threading; -using Umbraco.Core.Configuration; -using Umbraco.Core.Diagnostics; using Serilog; using Serilog.Events; -using Umbraco.Core.Logging.SerilogExtensions; +using Umbraco.Core.Configuration; +using Umbraco.Core.Diagnostics; -namespace Umbraco.Core.Logging +namespace Umbraco.Core.Logging.Serilog { /// /// Implements on top of Serilog. /// - public class Logger : ILogger + public class SerilogLogger : ILogger { /// - /// Initialize a new instance of the class with a configuration file. + /// Initialize a new instance of the class with a configuration file. /// /// - public Logger(FileInfo logConfigFile) + public SerilogLogger(FileInfo logConfigFile) { Log.Logger = new LoggerConfiguration() .ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + logConfigFile) .CreateLogger(); } - public Logger(LoggerConfiguration logConfig) + public SerilogLogger(LoggerConfiguration logConfig) { //Configure Serilog static global logger with config passed in Log.Logger = logConfig.CreateLogger(); } /// - /// Creates a logger with some pre-definied configuration and remainder from config file + /// Creates a logger with some pre-defined configuration and remainder from config file /// /// Used by UmbracoApplicationBase to get its logger. - public static Logger CreateWithDefaultConfiguration() + public static SerilogLogger CreateWithDefaultConfiguration() { var loggerConfig = new LoggerConfiguration(); loggerConfig @@ -46,78 +45,118 @@ namespace Umbraco.Core.Logging .ReadFromConfigFile() .ReadFromUserConfigFile(); - return new Logger(loggerConfig); + return new SerilogLogger(loggerConfig); } + /// + /// Gets a contextualized logger. + /// + private global::Serilog.ILogger LoggerFor(Type reporting) + => Log.Logger.ForContext(reporting); + + /// + /// Maps Umbraco's log level to Serilog's. + /// + private LogEventLevel MapLevel(LogLevel level) + { + switch (level) + { + case LogLevel.Debug: + return LogEventLevel.Debug; + case LogLevel.Error: + return LogEventLevel.Error; + case LogLevel.Fatal: + return LogEventLevel.Fatal; + case LogLevel.Information: + return LogEventLevel.Information; + case LogLevel.Verbose: + return LogEventLevel.Verbose; + case LogLevel.Warning: + return LogEventLevel.Warning; + } + + throw new NotSupportedException($"LogLevel \"{level}\" is not supported."); + } + + /// + public bool IsEnabled(Type reporting, LogLevel level) + => LoggerFor(reporting).IsEnabled(MapLevel(level)); + /// public void Fatal(Type reporting, Exception exception, string message) { - Fatal(reporting, exception, message, null); + var logger = LoggerFor(reporting); + DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref message); + logger.Fatal(exception, message); } /// public void Fatal(Type reporting, Exception exception) { - Fatal(reporting, exception, string.Empty); + var logger = LoggerFor(reporting); + var message = "Exception."; + DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref message); + logger.Fatal(exception, message); } /// public void Fatal(Type reporting, string message) { - //Sometimes we need to throw an error without an ex - Fatal(reporting, null, message); + LoggerFor(reporting).Fatal(message); } /// public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) { - //Log a structured message WITHOUT an ex - Fatal(reporting, null, messageTemplate, propertyValues); + LoggerFor(reporting).Fatal(messageTemplate, propertyValues); } /// public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - ErrorOrFatal(Fatal, exception, ref messageTemplate); - var logger = Log.Logger; - logger?.ForContext(reporting).Fatal(exception, messageTemplate, propertyValues); + var logger = LoggerFor(reporting); + DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref messageTemplate); + logger.Fatal(exception, messageTemplate, propertyValues); } /// public void Error(Type reporting, Exception exception, string message) { - Error(reporting, exception, message, null); + var logger = LoggerFor(reporting); + DumpThreadAborts(logger, LogEventLevel.Error, exception, ref message); + logger.Error(exception, message); } /// public void Error(Type reporting, Exception exception) { - Error(reporting, exception, string.Empty); + var logger = LoggerFor(reporting); + var message = "Exception"; + DumpThreadAborts(logger, LogEventLevel.Error, exception, ref message); + logger.Error(exception, message); } /// public void Error(Type reporting, string message) { - //Sometimes we need to throw an error without an ex - Error(reporting, null, message); + LoggerFor(reporting).Error(message); } /// public void Error(Type reporting, string messageTemplate, params object[] propertyValues) { - //Log a structured message WITHOUT an ex - Error(reporting, null, messageTemplate, propertyValues); + LoggerFor(reporting).Error(messageTemplate, propertyValues); } /// public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - ErrorOrFatal(Error, exception, ref messageTemplate); - var logger = Log.Logger; - logger?.ForContext(reporting).Error(exception, messageTemplate, propertyValues); + var logger = LoggerFor(reporting); + DumpThreadAborts(logger, LogEventLevel.Error, exception, ref messageTemplate); + logger.Error(exception, messageTemplate, propertyValues); } - private static void ErrorOrFatal(Action logAction, Exception exception, ref string messageTemplate) + private static void DumpThreadAborts(global::Serilog.ILogger logger, LogEventLevel level, Exception exception, ref string messageTemplate) { var dump = false; @@ -143,8 +182,10 @@ namespace Umbraco.Core.Logging } catch (Exception ex) { + messageTemplate += "\r\nFailed to create a minidump"; + //Log a new entry (as opposed to appending to same log entry) - logAction(ex.GetType(), ex, "Failed to create a minidump at App_Data/MiniDump ({ExType}: {ExMessage}", + logger.Write(level, ex, "Failed to create a minidump ({ExType}: {ExMessage})", new object[]{ ex.GetType().FullName, ex.Message }); } } @@ -174,69 +215,63 @@ namespace Umbraco.Core.Logging } /// - public void Warn(Type reporting, string format) + public void Warn(Type reporting, string message) { - Warn(reporting, null, format); + LoggerFor(reporting).Warning(message); } /// - public void Warn(Type reporting, string messageTemplate, params object[] propertyValues) + public void Warn(Type reporting, string message, params object[] propertyValues) { - Warn(reporting, null, messageTemplate, propertyValues); + LoggerFor(reporting).Warning(message, propertyValues); } /// public void Warn(Type reporting, Exception exception, string message) { - Warn(reporting, exception, message, Array.Empty()); + LoggerFor(reporting).Warning(exception, message); } /// public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - var logger = Log.Logger; - logger?.ForContext(reporting).Warning(exception, messageTemplate, propertyValues); + LoggerFor(reporting).Warning(exception, messageTemplate, propertyValues); } /// public void Info(Type reporting, string message) { - Info(reporting, message, Array.Empty()); + LoggerFor(reporting).Information(message); } /// public void Info(Type reporting, string messageTemplate, params object[] propertyValues) { - var logger = Log.Logger; - logger?.ForContext(reporting).Information(messageTemplate, propertyValues); + LoggerFor(reporting).Information(messageTemplate, propertyValues); } /// public void Debug(Type reporting, string message) { - Debug(reporting, message, Array.Empty()); + LoggerFor(reporting).Debug(message); } /// public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) { - var logger = Log.Logger; - logger?.ForContext(reporting).Debug(messageTemplate, propertyValues); + LoggerFor(reporting).Debug(messageTemplate, propertyValues); } /// public void Verbose(Type reporting, string message) { - Verbose(reporting, message, Array.Empty()); + LoggerFor(reporting).Verbose(message); } /// public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) { - var logger = Log.Logger; - logger?.ForContext(reporting).Verbose(messageTemplate, propertyValues); + LoggerFor(reporting).Verbose(messageTemplate, propertyValues); } - - } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ba18f1e063..755024d72d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -329,9 +329,10 @@ + - - + + @@ -570,7 +571,7 @@ - + diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index c461d9f824..1304244ece 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -4,10 +4,9 @@ using System.Threading; using System.Web; using System.Web.Hosting; using LightInject; -using Serilog; using Umbraco.Core.Composing; using Umbraco.Core.Logging; -using ILogger = Umbraco.Core.Logging.ILogger; +using Umbraco.Core.Logging.Serilog; namespace Umbraco.Core { @@ -28,7 +27,7 @@ namespace Umbraco.Core /// protected virtual ILogger GetLogger() { - return Logger.CreateWithDefaultConfiguration(); + return SerilogLogger.CreateWithDefaultConfiguration(); } // events - in the order they trigger @@ -161,13 +160,6 @@ namespace Umbraco.Core _runtime = null; } - // dispose the container and everything - // but first, capture the looger! - var logger = Current.Logger; - Current.Reset(); - - if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted) return; - // try to log the detailed shutdown message (typical asp.net hack: http://weblogs.asp.net/scottgu/433194) try { @@ -185,7 +177,7 @@ namespace Umbraco.Core BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null); - logger.Info("Application shutdown. Details: {ShutdownReason}\r\n\r\n_shutDownMessage={ShutdownMessage}\r\n\r\n_shutDownStack={ShutdownStack}", + Current.Logger.Info("Application shutdown. Details: {ShutdownReason}\r\n\r\n_shutDownMessage={ShutdownMessage}\r\n\r\n_shutDownStack={ShutdownStack}", HostingEnvironment.ShutdownReason, shutDownMessage, shutDownStack); @@ -193,20 +185,19 @@ namespace Umbraco.Core catch (Exception) { //if for some reason that fails, then log the normal output - logger.Info("Application shutdown. Reason: {ShutdownReason}", HostingEnvironment.ShutdownReason); + Current.Logger.Info("Application shutdown. Reason: {ShutdownReason}", HostingEnvironment.ShutdownReason); } + + // dispose the container and everything + Current.Reset(); } // called by ASP.NET (auto event wireup) once per app domain // sender is System.Web.HttpApplicationFactory, evargs is EventArgs.Empty protected void Application_End(object sender, EventArgs evargs) { - HandleApplicationEnd(); OnApplicationEnd(sender, evargs); - - //Not sure if we need to do this - as my POC approach I never had to deal with this - //As the LightInject container when tearing down will dispose of Serilog AFAIK - Log.CloseAndFlush(); + HandleApplicationEnd(); } #endregion diff --git a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs b/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs index 2026386e8a..a3e36db363 100644 --- a/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs +++ b/src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs @@ -5,6 +5,9 @@ namespace Umbraco.Tests.TestHelpers { public class ConsoleLogger : ILogger { + public bool IsEnabled(Type reporting, LogLevel level) + => true; + public void Fatal(Type reporting, Exception exception, string message) { Console.WriteLine("FATAL {0} - {1}", reporting.Name, message); @@ -22,15 +25,15 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine("FATAL {0} - {1}", reporting.Name, message); } - public void Fatal(Type reporting, Exception exception, string format, params object[] args) + public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("FATAL {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); Console.WriteLine(exception); } - public void Fatal(Type reporting, string format, params object[] args) + public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("FATAL {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); } public void Error(Type reporting, Exception exception, string message) @@ -50,15 +53,15 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine("ERROR {0} - {1}", reporting.Name, message); } - public void Error(Type reporting, Exception exception, string format, params object[] args) + public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("ERROR {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); Console.WriteLine(exception); } - public void Error(Type reporting, string format, params object[] args) + public void Error(Type reporting, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("ERROR {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); } public void Warn(Type reporting, string message) @@ -66,9 +69,9 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine("WARN {0} - {1}", reporting.Name, message); } - public void Warn(Type reporting, string format, params object[] args) + public void Warn(Type reporting, string message, params object[] propertyValues) { - Console.WriteLine("WARN {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("WARN {0} - {1}", reporting.Name, MessageTemplates.Render(message, propertyValues)); } public void Warn(Type reporting, Exception exception, string message) @@ -77,15 +80,15 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine(exception); } - public void Warn(Type reporting, Exception exception, string format, params object[] args) + public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues) { - Console.WriteLine("WARN {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("WARN {0} - {1}", reporting.Name, MessageTemplates.Render(message, propertyValues)); Console.WriteLine(exception); } - public void Info(Type reporting, string format, params object[] args) + public void Info(Type reporting, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("INFO {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("INFO {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); } public void Info(Type reporting, string message) @@ -98,9 +101,9 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine("DEBUG {0} - {1}", reporting.Name, message); } - public void Debug(Type reporting, string format, params object[] args) + public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("DEBUG {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("DEBUG {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); } public void Verbose(Type reporting, string message) @@ -108,9 +111,9 @@ namespace Umbraco.Tests.TestHelpers Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, message); } - public void Verbose(Type reporting, string format, params object[] args) + public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) { - Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, MessageTemplates.Render(format, args)); + Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, MessageTemplates.Render(messageTemplate, propertyValues)); } } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 3e40a7c3f7..ee521a7119 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; +using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Manifest; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; @@ -167,7 +168,7 @@ namespace Umbraco.Tests.Testing } else if (option == UmbracoTestOptions.Logger.Serilog) { - Container.RegisterSingleton(f => new Logger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config")))); + Container.RegisterSingleton(f => new SerilogLogger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config")))); Container.RegisterSingleton(f => new LogProfiler(f.GetInstance())); } diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 1e5e909bde..5ca195849b 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -1,15 +1,10 @@ -using Moq; -using System.IO; -using LightInject; +using System.IO; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Profiling; +using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; -using Umbraco.Examine; namespace Umbraco.Tests.UmbracoExamine { @@ -19,18 +14,12 @@ namespace Umbraco.Tests.UmbracoExamine [OneTimeSetUp] public void InitializeFixture() { - var logger = new Logger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); + var logger = new SerilogLogger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))); _profilingLogger = new ProfilingLogger(logger, new LogProfiler(logger)); } private ProfilingLogger _profilingLogger; - protected override ProfilingLogger ProfilingLogger - { - get - { - return _profilingLogger; - } - } + protected override ProfilingLogger ProfilingLogger => _profilingLogger; /// /// sets up resolvers before resolution is frozen