0

I have configured Seq for my local Sitecore instance.

  1. After an error is logged, it takes around 3 mins to show up in Seq. Can we configure it to display real-time.

  2. I do not see the exception & stack trace as shown in snap. What needs to be configured to view them.

enter image description here

UPDATE:

Reference: https://himadritechblog.wordpress.com/2020/11/14/serilog-appender-for-sitecore-logging/

After installing & setting up Seq, I have configured its API key & Host URL in my instance's webconfig

I have also configured Serilog appender like this. That is why I'm able to see all the logs. But just not the exception details.

Foundation.Logging.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:security="http://www.sitecore.net/xmlconfig/security/">
  <sitecore role:require="Standalone or ContentDelivery or ContentManagement">
    <log4net>
      <appender name="SerilogAppender" type="Foundation.Logging.Serilog.SerilogAppender, Foundation.Logging" patch:after = "appender[@name='LogFileAppender']">
        <minimumlevel value="DEBUG" />        
        <layout type="log4net.Layout.PatternLayout" />
        <encoding value="utf-8" />
      </appender>
      <root>
        <appender-ref ref="SerilogAppender" patch:after = "*[@ref='LogFileAppender']"/>
      </root>
    </log4net>
  </sitecore>
</configuration>

SerilogAppender.cs

using global::Serilog;
using global::Serilog.Core;
using global::Serilog.Events;
using log4net.Appender;
using log4net.helpers;
using log4net.spi;
using System;
using System.Configuration;

public class SerilogAppender : BufferingAppenderSkeleton
    {
        private string _minimumLevel;
        
        public string MinimumLevel
        {
            get => this._minimumLevel;
            set => this._minimumLevel = value;
        }

        public string ApiKey
        {
            //get => _apiKey;
            //set => _apiKey = value;
            get
            {
                return ConfigurationManager.AppSettings["SeqApiKey"];
            }
        }

        public string SeqHost
        {
            //get => _seqHost;
            //set => _seqHost = value;
            get
            {
                return ConfigurationManager.AppSettings["SeqHostUrl"];
            }
        }

        [Obsolete("Use the BufferingAppenderSkeleton Fix methods")]
        public bool LocationInfo
        {
            get
            {
                return false;
            }
            set
            {
            }
        }

        protected override void SendBuffer(LoggingEvent[] events)
        {
            using (var log = new LoggerConfiguration()
                .MinimumLevel.ControlledBy(new LoggingLevelSwitch(GetLogEventLevel()))
                .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);
                }
            }

        }

        protected override bool RequiresLayout => true;

        private void LogEvent(Logger log, LoggingEvent loggingEvent)
        {
            try
            {
                if (loggingEvent.Level == Level.DEBUG)
                {
                    log.Debug(loggingEvent.RenderedMessage);
                }
                if (loggingEvent.Level == Level.INFO)
                {
                    log.Information(loggingEvent.RenderedMessage);
                }
                if (loggingEvent.Level == Level.WARN)
                {
                    log.Warning(loggingEvent.RenderedMessage);
                }
                if (loggingEvent.Level == Level.ERROR)
                {
                    log.Error(loggingEvent.RenderedMessage);
                }
                if (loggingEvent.Level == Level.FATAL)
                {
                    log.Fatal(loggingEvent.RenderedMessage);
                }
            }
            catch (Exception ex)
            {
                this.ErrorHandler.Error("Error occurred while logging the event.", ex);
            }
        }
        private LogEventLevel GetLogEventLevel()
        {
            var logEventLevel = LogEventLevel.Debug;
            switch (MinimumLevel.ToLower())
            {
                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;
        }
    }
2
  • These questions are unique to Seq and would require knowledge of that product documentation. What have you tried after having read the docs? Commented Feb 6, 2023 at 13:47
  • @MichaelWest I'm new to Seq and following the doc, I have set it up. Then I have added its API key & host url in my instance's web.config. Also added the Serilog appender patch & class that I have now updated in my question.
    – sukesh
    Commented Feb 7, 2023 at 4:24

2 Answers 2

1

The version of log4net included with Sitecore should have a method on the LoggingEvent specifically for getting the exception error string.

When logging you should use both the RenderedMessage and GetExceptionStrRep().

1
  • That worked. But I'm able to add it only in the Title i.e. the whole exception shows beside "STRATUM_ERROR". How can we add it in the collapsible section. msg.AppendLine(loggingEvent.RenderedMessage); msg.AppendLine(loggingEvent.GetExceptionStrRep()); log.Error(msg.ToString());
    – sukesh
    Commented Feb 8, 2023 at 4:50
1

It's a better approach to format the event log message, as you're using layout:

<layout type="log4net.Layout.PatternLayout" />

This layout can format the message for your. So then you can use default method:

// instead of loggingEvent.RenderedMessage
// instead of loggingEvent.GetExceptionStrRep()
string message = RenderLoggingEvent(loggingEvent);

the final code is this:

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)
    {
        using (var log = new LoggerConfiguration()
            .MinimumLevel.ControlledBy(new LoggingLevelSwitch(GetLogEventLevel(MinimumLevel, LogEventLevel.Information)))
            .Enrich.FromLogContext()
            .Enrich.WithMachineName()
            .Enrich.WithEnvironmentUserName()
            .Enrich.WithProcessId()
            .Enrich.WithProcessName()
            .Enrich.WithProperty("ThreadId", SystemInfo.CurrentThreadId)
            .Enrich.WithProperty("Site", GetSite())
            .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;
    }

    protected override bool RequiresLayout => true;

    private void LogEvent(ILogger log, LoggingEvent loggingEvent)
    {
        try
        {
            // key change
            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;
    }
}

Note.You can control bufferSize for local (or any) environment to make log messages appear in SEQ really quickly (instead only when 512 messages are logged they will be sent):

<appender name="SerilogAppender" type="[YOUR_NAMESPACE].SerilogAppender, [YOUR_DLL]"
          patch:after="appender[@name='LogFileAppender']">
  <minimumlevel value="INFO" />
  <apikey value="$(env:SEQ_API_KEY)" />
  <seqhost value="$(env:SEQ_URL)" />
  <layout type="log4net.Layout.PatternLayout" />
  <encoding value="utf-8" />
  <bufferSize value="10" /> <!-- HERE you can set your buffer size value (default is 512) -->
</appender>

or using config transformation:

<log4net>
  <appender name="SerilogAppender" xdt:Locator="Match(name)">
    <bufferSize value="10" xdt:Transform="Insert" />
  </appender>
</log4net>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.