Last active
November 15, 2024 21:26
-
-
Save AldeRoberge/b88cc971fbe86d52aaf6b9bfe5ca6597 to your computer and use it in GitHub Desktop.
The Logging config I use for all my apps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.DependencyInjection; | |
using Serilog; | |
using Serilog.Events; | |
using Serilog.Exceptions; | |
using Serilog.Sinks.SystemConsole.Themes; | |
namespace ADG.Library.Logging | |
{ | |
public static class LoggingConfig | |
{ | |
// Configure the Serilog logger | |
public static void ConfigureLogger(LogEventLevel minimumLevel = LogEventLevel.Information) | |
{ | |
// Ensure Logs folder exists | |
Directory.CreateDirectory("Logs"); | |
// Define the log output template | |
var outputTemplate = | |
"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:w3} {FilePath}.{Method}:{LineNumber}] " + // Timestamp with milliseconds and log level | |
"{Message}" + // Log message | |
"{NewLine}{Exception}"; // Exception details (if any) | |
// Configure the logger | |
var config = new LoggerConfiguration() | |
.MinimumLevel.Is(minimumLevel) | |
.MinimumLevel.Override("Microsoft", minimumLevel) | |
.Enrich.WithExceptionDetails() | |
.Enrich.FromLogContext() | |
.WriteTo.Console(theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate) | |
.WriteTo.File("Logs/ADG-Log.txt", | |
LogEventLevel.Warning, | |
outputTemplate: outputTemplate, | |
rollingInterval: RollingInterval.Day); | |
// Set the minimum log level | |
// Create the logger | |
Log.Logger = config.CreateLogger(); | |
} | |
// Enables the use of the Serilog logger in Dependency Injection | |
public static void ConfigureLogger(this IServiceCollection services) | |
{ | |
ConfigureLogger(); | |
services.AddSingleton(Log.Logger); | |
} | |
} | |
} | |
using System; | |
using System.Diagnostics; | |
using Serilog; | |
using Serilog.Context; | |
using Serilog.Core; | |
namespace ADG.Shared.Logging | |
{ | |
public static class LoggerExtensions | |
{ | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogInformation(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Information)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Information(messageTemplate, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogWarning(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Warning)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Warning(messageTemplate, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogError(this ILogger? logger, Exception exception, string messageTemplate, | |
params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Error)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Error(exception, messageTemplate, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogError(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Error)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Error(messageTemplate, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogError(this ILogger? logger, Exception exception, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Error)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Error(exception, string.Empty, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogError(this ILogger? logger, string messageTemplate, Exception exception, | |
params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Error)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Error(exception, messageTemplate, propertyValues); | |
} | |
} | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogVerbose(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Verbose)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Verbose(messageTemplate, propertyValues); | |
} | |
} | |
// Log Fatal | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogFatal(this ILogger? logger, Exception exception, string messageTemplate, | |
params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Fatal)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Fatal(exception, messageTemplate, propertyValues); | |
} | |
} | |
// Log Fatal without exception | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogFatal(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Fatal)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Fatal(messageTemplate, propertyValues); | |
} | |
} | |
// Log Fatal without message | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogFatal(this ILogger? logger, Exception exception, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Fatal)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Fatal(exception, string.Empty, propertyValues); | |
} | |
} | |
// Log Fatal with exception and message | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogFatal(this ILogger? logger, string messageTemplate, Exception exception, | |
params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Fatal)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Fatal(exception, messageTemplate, propertyValues); | |
} | |
} | |
// Log Debug | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogDebug(this ILogger? logger, string messageTemplate, params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Debug)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Debug(messageTemplate, propertyValues); | |
} | |
} | |
// Log Verbose | |
[MessageTemplateFormatMethod("messageTemplate")] | |
public static void LogVerbose(this ILogger? logger, Exception exception, string messageTemplate, | |
params object[] propertyValues) | |
{ | |
logger ??= Log.Logger; | |
if (logger is Logger log && !log.IsEnabled(Serilog.Events.LogEventLevel.Verbose)) | |
return; | |
var callerInfo = GetCallerInfo(); | |
using (LogContext.PushProperty("Method", $"{callerInfo.MethodName}.")) | |
using (LogContext.PushProperty("FilePath", $" {callerInfo.FileName}.")) | |
using (LogContext.PushProperty("LineNumber", callerInfo.LineNumber)) | |
{ | |
logger.Verbose(exception, messageTemplate, propertyValues); | |
} | |
} | |
private static (string MethodName, string FileName, int LineNumber) GetCallerInfo() | |
{ | |
var stackTrace = new StackTrace(true); // Capture file info as well | |
var frame = stackTrace.GetFrame(2); // 2 to get the immediate caller of the logging method | |
var method = frame?.GetMethod(); | |
var methodName = method?.Name ?? "?"; | |
var fileName = frame?.GetFileName() ?? "?"; | |
var lineNumber = frame?.GetFileLineNumber() ?? 0; | |
return (methodName, GetFilePath(fileName), lineNumber); | |
} | |
private static string GetFilePath(string sourceFilePath) | |
{ | |
if (string.IsNullOrEmpty(sourceFilePath)) | |
return "UnknownFile"; | |
// Keep only the file name | |
var fileName = sourceFilePath.Substring(sourceFilePath.LastIndexOf("\\", StringComparison.Ordinal) + 1); | |
// Remove the file extension | |
// Ensure file name contains "." | |
if (fileName.IndexOf(".", StringComparison.Ordinal) == -1) | |
return fileName; | |
return fileName.Substring(0, fileName.LastIndexOf(".", StringComparison.Ordinal)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment