Cleanup logging

This commit is contained in:
Stephan
2018-08-30 19:08:55 +02:00
parent 8b4e2c5bcb
commit 4a32eebb0b
16 changed files with 273 additions and 260 deletions

View File

@@ -58,6 +58,7 @@ namespace Umbraco.Core.Composing
// resets *everything* that is 'current'
internal static void Reset()
{
_container?.Dispose();
_container = null;
_shortStringHelper = null;

View File

@@ -7,6 +7,9 @@ namespace Umbraco.Core.Logging
/// </summary>
public class DebugDiagnosticsLogger : ILogger
{
public bool IsEnabled(Type reporting, LogLevel level)
=> true;
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string message)
{
@@ -26,15 +29,15 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@@ -56,27 +59,27 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@@ -86,9 +89,9 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@@ -98,9 +101,9 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@@ -110,9 +113,9 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@@ -122,9 +125,9 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
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);
}
}
}

View File

@@ -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

View File

@@ -14,6 +14,13 @@ namespace Umbraco.Core.Logging
/// </remarks>
public interface ILogger
{
/// <summary>
/// Determines if logging is enabled at a specified level, for a reporting type.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="level">The level.</param>
bool IsEnabled(Type reporting, LogLevel level);
/// <summary>
/// Logs a fatal message with an exception.
/// </summary>

View File

@@ -0,0 +1,15 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Specifies the level of a log event.
/// </summary>
public enum LogLevel
{
Verbose,
Debug,
Information,
Warning,
Error,
Fatal
}
}

View File

@@ -8,63 +8,62 @@ namespace Umbraco.Core.Logging
public static class LoggerExtensions
{
/// <summary>
/// Logs an error message
/// Determines if logging is enabled at a specified level, for a reporting type.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="level">The level.</param>
public static bool IsEnabled<T>(this ILogger logger, LogLevel level)
=> logger.IsEnabled(typeof(T), level);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, Exception exception, string message)
{
logger.Error(typeof(T), exception, message);
}
=> logger.Error(typeof(T), exception, message);
/// <summary>
/// Logs an error message with a structured message template
/// Logs an error message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="exception">An exception</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Error<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Error(typeof(T), exception, messageTemplate, propertyValues);
}
=> logger.Error(typeof(T), exception, messageTemplate, propertyValues);
/// <summary>
/// Logs an error message NOTE: This will log an empty message string
/// Logs an error exception.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception</param>
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, Exception exception)
{
logger.Error(typeof(T), exception);
}
=> logger.Error(typeof(T), exception);
/// <summary>
/// Logs an error message WITHOUT EX
/// Logs an error message.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="logger"></param>
/// <param name="message"></param>
public static void Error<T>(this ILogger logger, string message)
{
logger.Error(typeof(T), message);
}
/// <summary>
/// Logs an error message - using a structured log message
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="message">A message.</param>
public static void Error<T>(this ILogger logger, string message)
=> logger.Error(typeof(T), message);
/// <summary>
/// Logs an error message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Error<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Error(typeof(T), messageTemplate, propertyValues);
}
=> logger.Error(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a warning message.
@@ -73,46 +72,38 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Warn<T>(this ILogger logger, string message)
{
logger.Warn(typeof(T), message);
}
=> logger.Warn(typeof(T), message);
/// <summary>
/// Logs a warning message with a structured message template
/// Logs a warning message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Warn<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Warn(typeof(T), messageTemplate, propertyValues);
}
=> logger.Warn(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a formatted warning message with an exception.
/// Logs a warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
public static void Warn<T>(this ILogger logger, Exception exception, string message)
{
logger.Warn(typeof(T), exception, message);
}
=> logger.Warn(typeof(T), exception, message);
/// <summary>
/// Logs a warning message with an exception with a structured message template
/// Logs a warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Warn<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Warn(typeof(T), exception, messageTemplate, propertyValues);
}
=> logger.Warn(typeof(T), exception, messageTemplate, propertyValues);
/// <summary>
/// Logs an information message.
@@ -121,21 +112,17 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Info<T>(this ILogger logger, string message)
{
logger.Info(typeof(T), message);
}
=> logger.Info(typeof(T), message);
/// <summary>
/// Logs a information message with a structured message template
/// Logs a information message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Info<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Info(typeof(T), messageTemplate, propertyValues);
}
=> logger.Info(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a debugging message.
@@ -144,21 +131,17 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Debug<T>(this ILogger logger, string message)
{
logger.Debug(typeof(T), message);
}
=> logger.Debug(typeof(T), message);
/// <summary>
/// Logs a debugging message with a structured message template
/// Logs a debugging message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Debug<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Debug(typeof(T), messageTemplate, propertyValues);
}
=> logger.Debug(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a verbose message.
@@ -167,22 +150,17 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Verbose<T>(this ILogger logger, string message)
{
logger.Verbose(typeof(T), message);
}
=> logger.Verbose(typeof(T), message);
/// <summary>
/// Logs a Verbose message with a structured message template
/// Logs a verbose message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Verbose<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Verbose(typeof(T), messageTemplate, propertyValues);
}
=> logger.Verbose(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a fatal message.
@@ -192,23 +170,17 @@ namespace Umbraco.Core.Logging
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string message)
{
logger.Fatal(typeof(T), exception, message);
}
=> logger.Fatal(typeof(T), exception, message);
/// <summary>
/// Logs a fatal message with a structured message template
/// Logs a fatal message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Fatal(typeof(T), exception, messageTemplate, propertyValues);
}
=> logger.Fatal(typeof(T), exception, messageTemplate, propertyValues);
}
}

View File

@@ -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<Serilog.ILogger> MinimalLogger = new Lazy<Serilog.ILogger>(() => new LoggerConfiguration().CreateLogger());
private static readonly Lazy<global::Serilog.ILogger> MinimalLogger = new Lazy<global::Serilog.ILogger>(() => 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));
}

View File

@@ -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<T>(string startMessage)
@@ -26,27 +24,33 @@ namespace Umbraco.Core.Logging
public DisposableTimer TraceDuration<T>(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<T>(string startMessage)
{
return DebugDuration<T>(startMessage, "Completed.");
return Logger.IsEnabled<T>(LogLevel.Debug)
? DebugDuration<T>(startMessage, "Completed.")
: null;
}
public DisposableTimer DebugDuration<T>(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<T>(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;
}
}
}

View File

@@ -1,7 +1,7 @@
using Serilog.Core;
using Serilog.Events;
namespace Umbraco.Core.Logging.SerilogExtensions
namespace Umbraco.Core.Logging.Serilog
{
/// <summary>
/// This is used to create a new property in Logs called 'Log4NetLevel'

View File

@@ -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
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
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" />

View File

@@ -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
{
///<summary>
/// Implements <see cref="ILogger"/> on top of Serilog.
///</summary>
public class Logger : ILogger
public class SerilogLogger : ILogger
{
/// <summary>
/// Initialize a new instance of the <see cref="Logger"/> class with a configuration file.
/// Initialize a new instance of the <see cref="SerilogLogger"/> class with a configuration file.
/// </summary>
/// <param name="logConfigFile"></param>
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();
}
/// <summary>
/// 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
/// </summary>
/// <remarks>Used by UmbracoApplicationBase to get its logger.</remarks>
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);
}
/// <summary>
/// Gets a contextualized logger.
/// </summary>
private global::Serilog.ILogger LoggerFor(Type reporting)
=> Log.Logger.ForContext(reporting);
/// <summary>
/// Maps Umbraco's log level to Serilog's.
/// </summary>
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.");
}
/// <inheritdoc/>
public bool IsEnabled(Type reporting, LogLevel level)
=> LoggerFor(reporting).IsEnabled(MapLevel(level));
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
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<Type, Exception, string, object[]> 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
}
/// <inheritdoc/>
public void Warn(Type reporting, string format)
public void Warn(Type reporting, string message)
{
Warn(reporting, null, format);
LoggerFor(reporting).Warning(message);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message)
{
Warn(reporting, exception, message, Array.Empty<object>());
LoggerFor(reporting).Warning(exception, message);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
public void Info(Type reporting, string message)
{
Info(reporting, message, Array.Empty<object>());
LoggerFor(reporting).Information(message);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
public void Debug(Type reporting, string message)
{
Debug(reporting, message, Array.Empty<object>());
LoggerFor(reporting).Debug(message);
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string message)
{
Verbose(reporting, message, Array.Empty<object>());
LoggerFor(reporting).Verbose(message);
}
/// <inheritdoc/>
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);
}
}
}

View File

@@ -329,9 +329,10 @@
<Compile Include="IO\MediaPathSchemes\OriginalMediaPathScheme.cs" />
<Compile Include="IO\MediaPathSchemes\TwoGuidsMediaPathScheme.cs" />
<Compile Include="KeyValuePairExtensions.cs" />
<Compile Include="Logging\LogLevel.cs" />
<Compile Include="Logging\MessageTemplates.cs" />
<Compile Include="Logging\SerilogExtensions\LoggerConfigExtensions.cs" />
<Compile Include="Logging\SerilogExtensions\Log4NetLevelMapperEnricher.cs" />
<Compile Include="Logging\Serilog\LoggerConfigExtensions.cs" />
<Compile Include="Logging\Serilog\Log4NetLevelMapperEnricher.cs" />
<Compile Include="Migrations\MigrationBase_Extra.cs" />
<Compile Include="Migrations\Upgrade\V_7_10_0\RenamePreviewFolder.cs" />
<Compile Include="Migrations\Upgrade\V_7_12_0\AddRelationTypeForMediaFolderOnDelete.cs" />
@@ -570,7 +571,7 @@
<Compile Include="Logging\ILogger.cs" />
<Compile Include="Logging\ImageProcessorLogger.cs" />
<Compile Include="Logging\IProfiler.cs" />
<Compile Include="Logging\Logger.cs" />
<Compile Include="Logging\Serilog\SerilogLogger.cs" />
<Compile Include="Logging\LoggerExtensions.cs" />
<Compile Include="Logging\LoggingTaskExtension.cs" />
<Compile Include="Logging\LogProfiler.cs" />

View File

@@ -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
/// </summary>
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<UmbracoApplicationBase>("Application shutdown. Details: {ShutdownReason}\r\n\r\n_shutDownMessage={ShutdownMessage}\r\n\r\n_shutDownStack={ShutdownStack}",
Current.Logger.Info<UmbracoApplicationBase>("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<UmbracoApplicationBase>("Application shutdown. Reason: {ShutdownReason}", HostingEnvironment.ShutdownReason);
Current.Logger.Info<UmbracoApplicationBase>("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

View File

@@ -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));
}
}
}

View File

@@ -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<ILogger>(f => new Logger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))));
Container.RegisterSingleton<ILogger>(f => new SerilogLogger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))));
Container.RegisterSingleton<IProfiler>(f => new LogProfiler(f.GetInstance<ILogger>()));
}

View File

@@ -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;
/// <summary>
/// sets up resolvers before resolution is frozen