Log4net: logging two messages on one line in a database?
I am trying to log the input and output of a specific method to the database. I would like to have this information in separate columns. I researched PatternLayout and it seems that it only serves one message parameter,%, which means that if you do:
log.Debug("This is a message");
then log4net sees "This message" as the log message. I want to do something like:
log.Debug(request, response);
Is this possible with log4net? Keep in mind that my goal is to have "request" and "response" columns separately .
a source to share
Your PatternConverter path is a step in the right direction, although using static input and output properties makes it a little shaky (from a security standpoint).
The trick here is to understand that the message parameter on logger.Debug (...) is an object and that you can pass whatever you want.
You can define the type of custom message
public class InputOutput
{
public string Input {get;set;}
public string Output {get;set;}
}
and then let your converters read either property
public class InputPatternConverter : PatternConverter
{
protected override void Convert(System.IO.TextWriter writer, object state)
{
var msg = ((LoggingEvent)state).MessageObject as InputOutput;
if (msg != null)
writer.Write(msg.Input);
}
}
public class OutputPatternConverter : PatternConverter
{
protected override void Convert(System.IO.TextWriter writer, object state)
{
var msg = ((LoggingEvent)state).MessageObject as InputOutput;
if (msg != null)
writer.Write(msg.Output);
}
}
logging becomes much cleaner
logger.Debug(new InputOutput { Input = ..., Output = ...});
Your configuration will be the same.
The tip, however, is to subclass PatternLayout and add converters to that class's constructor. This way you can also customize your config. This will not cause you to lose the% message token, your% input and% output tokens will be added in addition to all the markers that PatternLayout supports. So you can have a template like this:
"%date %message %newline%newline %input %newline%newline %output
Here's a quick implementation of the custom template template:
public class InputOutputPatternLayout : PatternLayout
{
public InputOutputPatternLayout()
{
AddConverter("input", typeof(InputPatternConverter));
AddConverter("output", typeof(OutputPatternConverter));
}
}
a source to share
I came up with one way to do this using custom PatternConverters
public class InputPatternConverter : PatternConverter
{
private static string _input;
public static string Input
{
get { return _input; }
set { _input = value; }
}
protected override void Convert(System.IO.TextWriter writer, object state)
{
writer.Write(Input);
}
}
public class OutputPatternConverter : PatternConverter
{
private static string _output;
public static string Output
{
get { return _output; }
set { _output = value; }
}
protected override void Convert(System.IO.TextWriter writer, object state)
{
writer.Write(Output);
}
}
Agent specification:
<appender name="ADONetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=servername;initial catalog=database;Integrated Security=SSPI;" />
<commandText value="INSERT INTO RequestLog ([input], [output]) VALUES (@input, @output)" />
<parameter>
<parameterName value="@input" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="input" />
<type value="InputPatternConverter, ApplicationName" />
</converter>
<conversionPattern value="%input" />
</layout>
</parameter>
<parameter>
<parameterName value="@output" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="output" />
<type value="OutputPatternConverter, ApplicationName" />
</converter>
<conversionPattern value="%output" />
</layout>
</parameter>
</appender>
Call it using:
InputPatternConverter.Input = inputString;
OutputPatternConverter.Output = outputString;
XmlConfigurator.Configure();
ILog logger = LogManager.GetLogger(typeof(ApplicationClassName));
logger.Debug("");
a source to share