1

I have created a custom log appender. This is from the default Sitecore.Logging.dll.

public class ApiLogger : log4net.Appender.ForwardingAppender
{
   public ApiLogger()
   {
     LogProperties = new List<KeyValuePair<string, string>>();
   }

   public ApiLogger(List<KeyValuePair<string, string>> logProperties)
   {
     LogProperties = logProperties;
   }

   public List<KeyValuePair<string, string>> LogProperties { get; set; }

   protected override void Append(LoggingEvent loggingEvent)
   {
       ///Send log to 3rd Party API
   }
}

and declared it like this:

<?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>    
    <log4net>
      <appender name="SeqLogger" type="MyApp.ApiLogger, MyApp" patch:after = "appender[@name='LogFileAppender']">            
        <layout type="log4net.Layout.PatternLayout" />
        <encoding value="utf-8" />
      </appender>
      <root>
        <level value="DEBUG" />
        <appender-ref ref="ApiLogger" patch:after = "*[@ref='LogFileAppender']"/>
      </root>
    </log4net>
  </sitecore>
</configuration>

This is the calling method

public ActionResult UpdateOrder()
{
   try
   {
      ///update order
   }
   catch(Exception ex)
   {
     Log.Error("", ex, this);
   }
}

When there is an error, the default Sitecore log.txt is created and after that, the Append() method is triggered, where I'm sending the log info to a 3rd party API.

This custom logging is working fine & I'm able to view the exception details in the 3rd Party portal.

However, on an error, I would like to also capture the "Order" details like Id, Name etc. The LogProperties was created for this but don't know how to use it.

The reason, I'm not calling the API directly in the UpdateOrder() method is, there are several other methods in the solution which have their respective details to be captured.

One approach I could think of is, passing a JSON string as the first parameter in the Log.Error() method, but then it's not possible to know if that string is a collection of properties or any custom message.

Is there a way to add the custom data to the LoggingEvent in the caller method itself, or any better way to achieve what I'm trying to.

2 Answers 2

1

I know it might not be the direct answer that you are looking for but it will provide you with some ideas or lead you closer to a possible way. You can explore conversionPattern to pass additional parameters.

In this case, It just adds this information to the existing (default) LogFileAppender. To do this, extended Sitecore’s SitecoreLogFileAppender class as follows:

public class SitecoreLogFileAppenderEx : log4net.Appender.SitecoreLogFileAppender
{
    protected override void Append(LoggingEvent loggingEvent)
    {
        var properties = loggingEvent.Properties;
 
        properties["scuser"] = string.Empty;
        properties["scitemid"] = string.Empty;
        properties["rawurl"] = string.Empty;
 
        // Only log ERRORS or higher level events
        if (Sitecore.Context.Site != null && loggingEvent.Level >= Level.ERROR)
        {
            if (Sitecore.Context.User != null)
                try { properties["scuser"] = Sitecore.Context.User.Name; }
                catch { }
            if (Sitecore.Context.Item != null)
                try { properties["scitemid"] = Sitecore.Context.Item.ID.ToString(); }
                catch { }
 
            try { properties["rawurl"] = Sitecore.Web.WebUtil.GetServerUrl() + Sitecore.Web.WebUtil.GetRawUrl(); }
            catch { }
        }
        base.Append(loggingEvent);
    }
}

Then modified the web.config log4net configuration to use appender and added the custom properties to the PatternLayout as follows.:

<appender name="LogFileAppender" type="log4net.Appender.SitecoreLogFileAppenderEx, Sitecore.Drexel.Logging">
    <file value="$(dataFolder)/logs/log.{date}.txt"/>
    <appendToFile value="true"/>
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%4t %d{ABSOLUTE} %-5p %c [%P{scuser} %P{scitemid} %P{rawurl}] %m%n"/>
    </layout>
</appender>

It is important to note that when specifying the parameters in the PatternLayout, you must use a capital “P”.

References: https://sitecorepm.wordpress.com/2011/02/17/adding-custom-parameters-to-the-log/

https://www.sentinelone.com/blog/log4net-configuration-logging/

Hope it helps!

1
  • Thank you but I'm not logging to a text file. scuser,item are global props and there is no need for pattern. I could do it directly in the Append method. In my case, I need to send specific props for example, of an order whose details keep changing and has to be passed at the caller method level.
    – sukesh
    Commented Mar 30, 2023 at 13:04
1

You can try using the below method. I got this example from a blog post where the need is to add username and URL to the log information.

So created a custom LogFileAppender worked for it.

Create a custom Appender that will inherit from the RollingFileAppender used by the default Appender.

public class CustomerInfoSitecoreLogFileAppender : log4net.Appender.RollingFileAppender
{
    protected override void Append(log4net.spi.LoggingEvent loggingEvent)  
    {  
 
     
    }  
}

Add the additional information using this. In this example we are passing logged in user information.

var user = AuthenticatedUserRepository.GetAuthenticatedUser();   
log4net.spi.LoggingEventData data = loggingEvent.GetLoggingEventData();   
var username = string.IsNullOrEmpty(user?.Name) ? "User not logged in" : user.Name;   
data.Message += $"\r\nLogin: {username}\r\nUrl: {HttpContext.Current?.Request.Url.AbsoluteUri}";   
log4net.spi.LoggingEvent ev = new log4net.spi.LoggingEvent(data);   
base.Append(ev);   

And use this patch file.

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">  
  <sitecore>  
   <log4net>  
     <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender, Sitecore.Logging">  
       <patch:attribute name="type">YOUR.NAMESPACE.CustomerInfoSitecoreLogFileAppender, YOUR.DLL</patch:attribute>  
     </appender>  
   </log4net>  
  </sitecore>  
 </configuration>  

So using loggingEvent.GetLoggingEventData you can pass your custom information and log this.

Hope this will give you some context.

Refer to this article for whole implementation.

https://www.sitecored.com/2020/07/add-username-to-sitecore-log.html

2
  • Could you pls explain how is this Append() different from the one in question. I can get the user & url details in my Append() method also..right? How can I pass an Order object, when there is an exception in the UpdateOrder() method. This means, I need to somehow access the LoggingEvent in the controller itself. Hope you got my question now.
    – sukesh
    Commented Mar 31, 2023 at 2:44
  • @sukesh If you check the code how they are passing the data using LoggingEventData. So I can suggest that you can use this one in your catch block and bind your data (in string format) and then you can get it in your logging event. Commented Mar 31, 2023 at 5:35

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.