using Common.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;
namespace Common.Logger;
///
/// Implements a Logger that uses the Serilog package to create log entries and distributes them into different sinks.
/// Implemented Sinks: File (rolling file), Debug ().
///
public class SerilogLogger : Logging.ILogger
{
private readonly LoggingLevelSwitch loggingLevelSwitch;
public event EventHandler? NewLogEntry;
public LogLevel CurrentMinimumLogLevel { get; private set; } = LogLevel.Undefined;
///
/// Constructor of a Logger that uses the Serilog package to create log entries and distributes them into different sinks.
///
///
/// path where the logfile shall be created.
/// rolling file is created with daily interval. date is automatically added to file name.
/// Example: "C:/log/log-.txt"
///
///
/// if true the log entries are written to .
/// Minimum level is ignored for this log entries, therefore every log entry will be logged.
///
public SerilogLogger(string logFilePath, bool logToDebug)
{
// create logging level switch and initialized with lowest level
this.loggingLevelSwitch = new LoggingLevelSwitch() { MinimumLevel = Serilog.Events.LogEventLevel.Verbose };
// create logger instance
if (logToDebug)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Debug()
.WriteTo.File(logFilePath,
rollingInterval: RollingInterval.Day,
levelSwitch: loggingLevelSwitch,
outputTemplate: "{Message:lj}") // outputTemplate = plain message, formatting is done inside log entry
.CreateLogger();
}
else
{
Log.Logger = new LoggerConfiguration()
.WriteTo.File(logFilePath,
rollingInterval: RollingInterval.Day,
levelSwitch: loggingLevelSwitch,
outputTemplate: "{Message:lj}") // outputTemplate = plain message, formatting is done inside log entry
.CreateLogger();
}
}
public void Initialize()
{
this.Initialize(LogLevel.Trace);
}
public void Initialize(LogLevel minimumLogLevel)
{
this.SetMinimumLogLevel(minimumLogLevel);
// Nothing else to do for this logger
}
public void SetMinimumLogLevel(LogLevel newMinimumLogLevel)
{
this.loggingLevelSwitch.MinimumLevel = this.ConvertGenericToSerilogLogLevel(newMinimumLogLevel);
this.CurrentMinimumLogLevel = newMinimumLogLevel;
}
private LogEventLevel ConvertGenericToSerilogLogLevel(LogLevel newMinimumLogLevel) => newMinimumLogLevel switch
{
LogLevel.Undefined => LogEventLevel.Verbose,
LogLevel.Trace => LogEventLevel.Verbose,
LogLevel.Debug => LogEventLevel.Debug,
LogLevel.Info => LogEventLevel.Information,
LogLevel.Warn => LogEventLevel.Warning,
LogLevel.Error => LogEventLevel.Error,
_ => throw new NotImplementedException($"'{nameof(ConvertGenericToSerilogLogLevel)}()' does not contain an entry for {nameof(LogLevel)} {newMinimumLogLevel}"),
};
public void StopLogging()
{
Log.CloseAndFlush();
}
private void CreateLogEntry(LogEntry logEntry)
{
var serilogEventLevel = this.ConvertGenericToSerilogLogLevel(logEntry.LogLevel);
// formatting is done inside logEntry.ToString() method => therefore log plain message text with right category
switch (serilogEventLevel)
{
case LogEventLevel.Verbose:
Log.Verbose(logEntry.ToString());
break;
case LogEventLevel.Debug:
Log.Debug(logEntry.ToString());
break;
case LogEventLevel.Information:
Log.Information(logEntry.ToString());
break;
case LogEventLevel.Warning:
Log.Warning(logEntry.ToString());
break;
case LogEventLevel.Error:
Log.Error(logEntry.ToString());
break;
case LogEventLevel.Fatal:
Log.Error(logEntry.ToString());
break;
default:
throw new NotImplementedException($"'{nameof(CreateLogEntry)}()' does not contain an implementation for {nameof(LogEventLevel)} {serilogEventLevel}.");
}
// Raise event (only if the log is wanted due to the configured log level)
if (logEntry.LogLevel <= this.CurrentMinimumLogLevel)
{
this.NewLogEntry?.Invoke(this, new NewLogEntryEventArgs(logEntry));
}
}
#region Logging methods
public void LogTrace(string message, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Trace, Message = message });
}
public void LogDebug(string message, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Debug, Message = message });
}
public void LogInfo(string message, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Info, Message = message });
}
public void LogWarn(string message, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Warn, Message = message });
}
public void LogError(string message, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Error, Message = message });
}
public void LogException(Exception exception, string category = "")
{
this.CreateLogEntry(new LogEntry { Category = category, LogLevel = LogLevel.Error, Exception = exception });
}
public void LogException(Exception exception, string message, string category = "")
{
this.CreateLogEntry(
new LogEntry
{
Category = category,
LogLevel = LogLevel.Error,
Message = message,
Exception = exception
});
}
#endregion
}