implemented SerilogLogger,

added to App Startup
master
Jonas Arnold 3 years ago
parent d40c7c63a8
commit 50dc48a3fc
  1. 3
      Common/Common.csproj
  2. 2
      Common/Logging/ILogger.cs
  3. 9
      Common/Logging/LogLevel.cs
  4. 168
      Common/Logging/SerilogLogger.cs
  5. 15
      MultiTerm.Wpf/App.xaml.cs

@ -8,6 +8,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
</ItemGroup>
</Project>

@ -10,7 +10,7 @@ public interface ILogger
/// <summary>
/// Event that is thrown whenever a new log entry was entered with any Log method.
/// </summary>
event EventHandler<NewLogEntryEventArgs> NewLogEntry;
event EventHandler<NewLogEntryEventArgs>? NewLogEntry;
/// <summary>
/// Initialize the Logger once before using it.

@ -2,13 +2,14 @@
/// <summary>
/// Level of a log entry.
/// Listed from lowest priority to highest priority.
/// </summary>
public enum LogLevel
{
Undefined = 0,
Error = 1,
Warn = 2,
Trace = 1,
Debug = 2,
Info = 3,
Debug = 4,
Trace = 5
Warn = 4,
Error = 5
}

@ -0,0 +1,168 @@
using Common.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;
namespace Common.Logger;
/// <summary>
/// Implements a Logger that uses the Serilog package to create log entries and distributes them into different sinks.
/// Implemented Sinks: File (rolling file), Debug (<see cref="System.Diagnostics.Debug"/>).
/// </summary>
public class SerilogLogger : Logging.ILogger
{
private readonly LoggingLevelSwitch loggingLevelSwitch;
public event EventHandler<NewLogEntryEventArgs>? NewLogEntry;
/// <summary>
/// Constructor of a Logger that uses the Serilog package to create log entries and distributes them into different sinks.
/// </summary>
/// <param name="logFilePath">
/// 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"
/// </param>
/// <param name="logToDebug">
/// if true the log entries are written to <see cref="System.Diagnostics.Debug"/>.
/// Minimum level is ignored for this log entries, therefore every log entry will be logged.
/// </param>
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
}

@ -1,10 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MultiTerm.Core.ViewModel;
using Common.StartupHelpers;
using System.Windows;
using MultiTerm.Core.Common;
using MultiTerm.Core.Helpers;
using Common.Logging;
using Common.Logger;
namespace MultiTerm.Wpf;
@ -19,6 +19,7 @@ public partial class App : Application
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<MainWindow>();
services.AddSingleton<ILogger>(new SerilogLogger("C:/log/multiterm-log-.txt", true));
// viewmodels
services.AddSingleton<ShellViewModel>();
@ -33,6 +34,11 @@ public partial class App : Application
{
await AppHost!.StartAsync();
// create logger and initialize
var logger = AppHost.Services.GetRequiredService<ILogger>();
logger.Initialize(LogLevel.Trace);
logger.LogInfo("Application started.", nameof(App));
// instanciate startup form and show
var startupForm = AppHost.Services.GetRequiredService<MainWindow>();
startupForm.Show();
@ -42,6 +48,11 @@ public partial class App : Application
protected override async void OnExit(ExitEventArgs e)
{
// log application exit and stop logger (if still available)
var logger = AppHost!.Services.GetRequiredService<ILogger>();
logger?.LogInfo("Application exited.", nameof(App));
logger?.StopLogging();
await AppHost!.StopAsync();
base.OnExit(e);
}

Loading…
Cancel
Save