Log4Net, how to add a custom field to my logging

C#Log4netAppender

C# Problem Overview


I use the log4net.Appender.AdoNetAppender appender.
My log4net table are the following fields [Date],[Thread],[Level],[Logger],[Message],[Exception]

I would need to add another field to the log4net table (e.g SalesId), but how would I specify in my xml and in code to log the "SalesId" when logging a Error or Info message?

e.g. log.Info("SomeMessage", SalesId)

Here's the log4net xml

  <appender name="SalesDBAppender" type="log4net.Appender.AdoNetAppender">
    <bufferSize value="1" />
    <connectionType value ="System.Data.SqlClient.SqlConnection" />
    <connectionString value="Data Source=..." />
    <commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
    <parameter>
      <parameterName value="@log_date" />
      <dbType value="DateTime" />
      <layout type="log4net.Layout.RawTimeStampLayout" />
    </parameter>
    <parameter>
      <parameterName value="@thread" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%thread" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@log_level" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@logger" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@message" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%message" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@exception" />
      <dbType value="String" />
      <size value="2000" />
      <layout type="log4net.Layout.ExceptionLayout" />
    </parameter>
  </appender>

C# Solutions


Solution 1 - C#

  1. Modify the command text: INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @CustomColumn)

  2. Add the parameter definition for the custom column:

  3. Then use one of log4net’s contexts to transfer values to the parameter:

    // thread properties... log4net.LogicalThreadContext.Properties["CustomColumn"] = "Custom value"; log.Info("Message");

    // ...or global properties log4net.GlobalContext.Properties["CustomColumn"] = "Custom value";

Solution 2 - C#

Three types of logging context available in Log4Net.

  1. Log4Net.GlobalContext :- This context shared across all application threads and domains.If two threads set the same property on GlobalContext, One Value will override the other.

  2. Log4Net.ThreadContext :- This context scope limited to calling thread. Here two threads can set same property to different values without overriding to each other.

  3. Log4Net.ThreadLogicalContext :- This context behaves similarly to the ThreadContext. if you're working with a custom thread pool algorithm or hosting the CLR, you may find some use for this one.

Add the following code to your program.cs file:

static void Main( string[] args )
{
    log4net.Config.XmlConfigurator.Configure();
    log4net.ThreadContext.Properties[ "myContext" ] = "Logging from Main";
    Log.Info( "this is an info message" );
    Console.ReadLine();
}

2) Add the parameter definition for the custom column:

  <log4net>      
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger (%property{myContext}) [%level]- %message%newline" />
      </layout>
    </appender> 
  </log4net>

Solution 3 - C#

Here is a working version with some personalized preferences. I added a custom column for storing a generated exception code.

  1. Add your custom column(exceptionCode here) to Log4net config:

  2. Log4NetExtentedLoggingCustomParameters.cs

    namespace Common.Utils.LogHelper { public class Log4NetExtentedLoggingCustomParameters { public string ExceptionCode { get; set; }

         public string Message { get; set; }
    
         public override string ToString()
         {
             return Message;
         }
     }
    

    }

  3. Log4NetExtentedLoggingPatternConverter.cs

    namespace Common.Utils.LogHelper { public class Log4NetExtentedLoggingPatternConverter : PatternConverter { protected override void Convert(TextWriter writer, object state) { if (state == null) { writer.Write(SystemInfo.NullText); return; }

             var loggingEvent = state as LoggingEvent;
             var messageObj = loggingEvent.MessageObject as Log4NetExtentedLoggingCustomParameters;
    
             if (messageObj == null)
             {
                 writer.Write(SystemInfo.NullText);
             }
             else
             {
                 switch (this.Option.ToLower()) //this.Option = "Code"
                 {
                     case "code": //config conversionPattern parameter -> %exceptionCode{Code}
                         writer.Write(messageObj.ExceptionCode);
                         break;  
                     default:
                         writer.Write(SystemInfo.NullText);
                         break;
                 }
             }
         }
     }
    

    }

  4. Log4NetExtentedLoggingPatternLayout.cs

    namespace Common.Utils.LogHelper { public class Log4NetExtentedLoggingPatternLayout : PatternLayout { public Log4NetExtentedLoggingPatternLayout() { var customConverter = new log4net.Util.ConverterInfo() { Name = "exceptionCode", Type = typeof(Log4NetExtentedLoggingPatternConverter) };

             AddConverter(customConverter);
         }
     }
    

    }

  5. Logger.cs // Enjoy your logger with new column! :)

    namespace Common.Utils.LogHelper { public class Logger { static ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

         public static string LogError(string message, Exception exception = null)
         {
             var logWithErrCode = GetLogWithErrorCode(message);
             Logger.Error(logWithErrCode, exception);
             return logWithErrCode.ExceptionCode;
         }
    
         private static Log4NetExtentedLoggingCustomParameters GetLogWithErrorCode(string message)
         {
             var logWithErrCode = new Log4NetExtentedLoggingCustomParameters();
             logWithErrCode.ExceptionCode = GenerateErrorCode(); //this method is absent for simplicity. Use your own implementation
             logWithErrCode.Message = message;
             return logWithErrCode;
         }
     }
    

    }

references:

http://blog.stvjam.es/2014/01/logging-custom-objects-and-fields-with

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEminemView Question on Stackoverflow
Solution 1 - C#Marcelo De ZenView Answer on Stackoverflow
Solution 2 - C#piyush guptaView Answer on Stackoverflow
Solution 3 - C#Ali KaracaView Answer on Stackoverflow