Skip to content

Instantly share code, notes, and snippets.

@izharikov
Created July 1, 2024 15:13
Show Gist options
  • Save izharikov/42801610f971b8d7981d35f04f45083d to your computer and use it in GitHub Desktop.
Save izharikov/42801610f971b8d7981d35f04f45083d to your computer and use it in GitHub Desktop.
Sitecore SEQ Logging
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;
}
}
}
// 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);
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