Log4Net, how to add a custom field to my logging
C#Log4netAppenderC# 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#
-
Modify the command text:
INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @CustomColumn)
-
Add the parameter definition for the custom column:
-
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.
-
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.
-
Log4Net.ThreadContext :- This context scope limited to calling thread. Here two threads can set same property to different values without overriding to each other.
-
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.
-
Add your custom column(exceptionCode here) to Log4net config:
-
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; } }
}
-
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; } } } }
}
-
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); } }
}
-
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