Created
July 1, 2024 15:13
-
-
Save izharikov/42801610f971b8d7981d35f04f45083d to your computer and use it in GitHub Desktop.
Sitecore SEQ Logging
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 log4net.spi; | |
using System; | |
using log4net.helpers; | |
using Serilog; | |
using Serilog.Core; | |
using Serilog.Events; | |
using ILogger = Serilog.ILogger; | |
namespace log4net.Appender | |
{ | |
public class SerilogAppender : BufferingAppenderSkeleton | |
{ | |
public string MinimumLevel { get; set; } | |
public string ApiKey { get; set; } | |
public string SeqHost { get; set; } | |
[Obsolete("Use the BufferingAppenderSkeleton Fix methods")] | |
public bool LocationInfo => false; | |
protected override void SendBuffer(LoggingEvent[] events) | |
{ | |
if (string.IsNullOrEmpty(SeqHost)) | |
{ | |
return; | |
} | |
using ( | |
var log = new LoggerConfiguration() | |
.MinimumLevel.ControlledBy(new LoggingLevelSwitch(GetLogEventLevel(MinimumLevel, LogEventLevel.Information))) | |
.Enrich.WithProperty("ApplicationName", GetSite()) | |
.Enrich.WithProperty("SpokeName", GetRoleName().ToLower()) | |
.Enrich.FromLogContext() | |
.Enrich.WithMachineName() | |
.Enrich.WithEnvironmentUserName() | |
.Enrich.WithProcessId() | |
.Enrich.WithProcessName() | |
.Enrich.WithProperty("ThreadId", SystemInfo.CurrentThreadId) | |
.Enrich.WithMemoryUsage() | |
.WriteTo.Seq(SeqHost, apiKey: ApiKey) | |
.CreateLogger() | |
) | |
{ | |
foreach (var thisEvent in events) | |
{ | |
LogEvent(log, thisEvent); | |
} | |
} | |
} | |
private static string GetSite() | |
{ | |
return !string.IsNullOrWhiteSpace(Sitecore.Context.Site?.Name) ? Sitecore.Context.Site.Name : null; | |
} | |
private static string GetRoleName() | |
{ | |
var roleName = Sitecore.Configuration.Settings.GetSetting("CloudRoleNameFallback"); | |
return !string.IsNullOrWhiteSpace(roleName) ? roleName : "RoleName"; | |
} | |
protected override bool RequiresLayout => true; | |
private void LogEvent(ILogger log, LoggingEvent loggingEvent) | |
{ | |
try | |
{ | |
var message = RenderLoggingEvent(loggingEvent); | |
var level = GetLogEventLevel(loggingEvent.Level.ToString()); | |
log.Write(level, message); | |
} | |
catch (Exception ex) | |
{ | |
ErrorHandler.Error("Error occurred while logging the event.", ex); | |
} | |
} | |
private static LogEventLevel GetLogEventLevel(string level, LogEventLevel defaultValue = LogEventLevel.Debug) | |
{ | |
var logEventLevel = defaultValue; | |
switch (level.ToLowerInvariant()) | |
{ | |
case "debug": | |
logEventLevel = LogEventLevel.Debug; | |
break; | |
case "info": | |
logEventLevel = LogEventLevel.Information; | |
break; | |
case "warn": | |
logEventLevel = LogEventLevel.Warning; | |
break; | |
case "error": | |
logEventLevel = LogEventLevel.Error; | |
break; | |
case "fatal": | |
logEventLevel = LogEventLevel.Fatal; | |
break; | |
} | |
return logEventLevel; | |
} | |
} | |
} |
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
// use reflection, because m_thrownException is private field in log4net.spi.LoggingEvent | |
FieldInfo ExceptionField = typeof(LoggingEvent).GetField("m_thrownException", | |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
// ... | |
Exception exception = null; | |
if (level >= LogEventLevel.Error) | |
{ | |
exception = ExceptionField.GetValue(loggingEvent) as Exception; | |
} | |
log.Write(level, exception, message); |
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 log4net.spi; | |
using System; | |
using System.Reflection; | |
using Serilog; | |
using Serilog.Core; | |
using Serilog.Events; | |
using ILogger = Serilog.ILogger; | |
using log4net.helpers; | |
using Serilog.Exceptions; | |
using SitecoreSerilog.Extensions; | |
// ReSharper disable once CheckNamespace | |
namespace log4net.Appender | |
{ | |
public class SerilogAppender : BufferingAppenderSkeleton | |
{ | |
public string MinimumLevel { get; set; } | |
public string ApiKey { get; set; } | |
public string SeqHost { get; set; } | |
[Obsolete("Use the BufferingAppenderSkeleton Fix methods")] | |
public bool LocationInfo => false; | |
private Logger _seqLogger; | |
private static readonly FieldInfo ExceptionField = typeof(LoggingEvent).GetField("m_thrownException", | |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
protected override void SendBuffer(LoggingEvent[] events) | |
{ | |
if (_seqLogger == null) | |
{ | |
return; | |
} | |
foreach (var thisEvent in events) | |
{ | |
LogEvent(_seqLogger, thisEvent); | |
} | |
} | |
protected override bool RequiresLayout => true; | |
private void LogEvent(ILogger log, LoggingEvent loggingEvent) | |
{ | |
try | |
{ | |
var message = RenderLoggingEvent(loggingEvent); | |
var level = GetLogEventLevel(loggingEvent.Level.ToString()); | |
Exception exception = null; | |
if (level >= LogEventLevel.Error) | |
{ | |
exception = ExceptionField.GetValue(loggingEvent) as Exception; | |
} | |
log.Write(level, exception, message); | |
} | |
catch (Exception ex) | |
{ | |
ErrorHandler.Error("Error occurred while logging the event.", ex); | |
} | |
} | |
private static LogEventLevel GetLogEventLevel(string level, LogEventLevel defaultValue = LogEventLevel.Debug) | |
{ | |
var logEventLevel = defaultValue; | |
switch (level.ToLowerInvariant()) | |
{ | |
case "debug": | |
logEventLevel = LogEventLevel.Debug; | |
break; | |
case "info": | |
logEventLevel = LogEventLevel.Information; | |
break; | |
case "warn": | |
logEventLevel = LogEventLevel.Warning; | |
break; | |
case "error": | |
logEventLevel = LogEventLevel.Error; | |
break; | |
case "fatal": | |
logEventLevel = LogEventLevel.Fatal; | |
break; | |
} | |
return logEventLevel; | |
} | |
public override void ActivateOptions() | |
{ | |
base.ActivateOptions(); | |
if (string.IsNullOrEmpty(SeqHost)) | |
{ | |
return; | |
} | |
_seqLogger = new LoggerConfiguration() | |
.MinimumLevel | |
.ControlledBy(new LoggingLevelSwitch(GetLogEventLevel(MinimumLevel, LogEventLevel.Information))) | |
.Enrich.WithFuncEnricher("ApplicationName", GetSite) | |
.Enrich.WithFuncEnricher("SpokeName", () => GetRoleName().ToLower()) | |
.Enrich.FromLogContext() | |
.Enrich.WithUtcTimestamp() | |
.Enrich.WithMachineName() | |
.Enrich.WithEnvironmentUserName() | |
.Enrich.WithProcessId() | |
.Enrich.WithProcessName() | |
.Enrich.WithFuncEnricher("ThreadId", () => SystemInfo.CurrentThreadId) | |
.Enrich.WithMemoryUsage() | |
.Enrich.WithExceptionDetails() | |
.WriteTo.Seq(SeqHost, apiKey: ApiKey, batchPostingLimit: BufferSize) | |
.CreateLogger(); | |
_seqLogger.Information("SEQ Initialized"); | |
} | |
public override void OnClose() | |
{ | |
base.OnClose(); | |
_seqLogger.Information("SEQ Disposing"); | |
_seqLogger?.Dispose(); | |
} | |
private static string GetSite() | |
{ | |
return !string.IsNullOrWhiteSpace(Sitecore.Context.Site?.Name) ? Sitecore.Context.Site.Name : "N/A"; | |
} | |
private static string GetRoleName() | |
{ | |
var roleName = Sitecore.Configuration.Settings.GetSetting("CloudRoleNameFallback"); | |
return !string.IsNullOrWhiteSpace(roleName) ? roleName : "RoleName"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment