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; /// /// 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); } 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}."); } } #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 }