Instead of manually adding properties at ILog.Info() call, I propose a forwarding appender that can take any message object, extract all public properties and add them to the properties hashtable. The code i wrote is inheriting the ForwardingAppender class.
// -- Usage example --
class DataMessage
{
DataMessage( string name, int age ) { Name=name; Age=age; }
public string Name;
public int Age;
public override string ToString()
{ return string.Format("{0} ({1})", Name, Age) ; }
}
. . .
logger.Info( new DataMessage( "Bob", 40 ) );
configuration file:
<appender name="DataPropertyAdder" type="LoggerExtensions.PropertyAdderAppender, LoggerExtensions">
<appender-ref ref="FileAppender" />
</appender>
A simple configuration file change will allow any complex logging, such as forwarding those properties into text / xml / sql database by using standard pattern layout class.
My biggest concern is how to do property rendering - properties are added as is to the hashtable, and i did not find a good way to specify formating. ToString() of each object will be used, but for example XmlLayout has no code to do xml property encoding.
Here's the PropertyAdder appender class.
// Submitted by Yuri Astrakhan (zapodlo at gmail dot com) for Log4net project.
//
/// <summary>
/// This appender modifies <see cref="LoggingEvent"/> by adding
/// all public properties of the message object to
/// the <see cref="LoggingEvent.Properties"/> hashtable
/// and forwards the event to the next appenders.
/// </summary>
public class PropertyAdderAppender : ForwardingAppender
{
#region Public Instance Constructors
/// <summary>
/// Initializes a new instance of the <see cref="PropertyAdderAppender" /> class.
/// </summary>
public PropertyAdderAppender()
{}
#endregion
#region Override implementation of ForwardingAppender
/// <summary>
/// This method is called by the <see cref="AppenderSkeleton.DoAppend"/>
/// method.
/// </summary>
/// <param name="loggingEvent">The event to log.</param>
override protected void Append(LoggingEvent loggingEvent)
{
// TODO: accessing indexed properties
// TODO: accessing sub-properties: a.b.c
// TODO: implement attribute-based property filtering
// TODO: implement customizable property name prefix// NOTE: objects do not need to be rendered at this stage, // besides, RenderMap is not easily accessible from here.
foreach( PropertyInfo propInfo in loggingEvent.MessageObject.GetType().
GetProperties( BindingFlags.Instance | BindingFlags.Public ))
{
if( propInfo.CanRead )
loggingEvent.Properties[propInfo.Name] =
propInfo.GetValue(loggingEvent.MessageObject, null);
} foreach( FieldInfo fldInfo in loggingEvent.MessageObject.GetType().
GetFields( BindingFlags.Instance | BindingFlags.Public ))
{
loggingEvent.Properties[fldInfo.Name] =
fldInfo.GetValue(loggingEvent.MessageObject);
}base.Append(loggingEvent); }
#endregion }
_________________________________________________________________
Is your PC infected? Get a FREE online computer virus scan from McAfee� Security. http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963
