Setup log4net in Web.Config is straight forward. Need to write Extension of ILog adding Task for Non-blocking Database write.
Web.Config
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler"/>
</configSections>
<log4net debug="false">
<appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<!--<connectionString value="Data Source=Pentium22;Initial Catalog=db;Integrated Security=True" />-->
<connectionString value="Data Source=Pentium22;Initial Catalog=db;User ID=sa;Password=xxxxxx;" />
<!--<commandText value="INSERT INTO LogMVC3 ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" />-->
<commandText value="INSERT INTO LogMVC3A ([Date],[Message]) VALUES (@log_date, @message)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%thread" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" value="%level" />
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%logger" />
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>
</appender>
<root>
<level value="All"/>
<appender-ref ref="AdoNetAppender_SqlServer"/>
</root>
</log4net>
Global.asax
protected void Application_Start()
{
...
log4net.Config.XmlConfigurator.Configure();
}
Note that for console app use [assembly: log4net.Config.XmlConfigurator(Watch = true)]
Extension for ILog:
public static class Class1
{
public static void Info2(this ILog log, object Message)
{
Task.Factory.StartNew(() =>
{
log.Info(Message);
Thread.Sleep(5000);
});
}
}
Logging anywhere w/o blocking:
public static class Class1
{
public static void Info2(this ILog log, object Message)
{
Task.Factory.StartNew(() =>
{
log.Info(Message);
Thread.Sleep(5000);
});
}
public static void Audit2(this ILog log, object auditData)
{
Task.Factory.StartNew(() =>
{
AuditDataWrapper adw = new AuditDataWrapper() { AuditData = auditData };
log.Info(adw);
Thread.Sleep(5000);
});
}
}
public class AuditDataWrapper
{
public object AuditData { get; set; }
}
Note:
root/level/value can be
OFF FATAL ERROR WARN INFO DEBUG ALL
bufferSize=1 means immediate write to DB, no delay/caching
Reference:
http://basquang.wordpress.com/2011/08/26/logging-using-log4net-in-asp-net-mvc-3/
Customization -AuditData Pattern Converter
public class AuditDataPatternLayoutConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
{
object obj = loggingEvent.MessageObject;
Type t = obj.GetType();
if (loggingEvent.Level != log4net.Core.Level.Info || t != typeof(AuditDataWrapper)) return;
AuditDataWrapper adw = obj as AuditDataWrapper;
if (adw.AuditData==null) return;
XmlSerializer ser = new XmlSerializer(adw.AuditData.GetType());
StringWriter sw = new StringWriter();
try
{
ser.Serialize(sw, adw.AuditData);
sw.Flush();
writer.Write(sw.ToString());
}
catch
{
string dump = DumpProperties(adw.AuditData, adw.AuditData.GetType());
writer.Write(dump);
}
}
string DumpProperties(object obj, Type t)
{
PropertyInfo[] pi = t.GetProperties();
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo p in pi)
sb.Append(p.Name + " :" + p.GetValue(obj, null) + "\r\n");
return sb.ToString();
}
}
<parameter>
<parameterName value="@auditdata" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="auditdata" />
<type value="MvcApplication3.AuditDataPatternLayoutConverter" />
</converter>
<conversionPattern value="%auditdata" />
</layout>
</parameter>
// Can put in any type of data into Audit
log.Audit2(new TestData()
{
Name = "John",
Age = 90,
id = WindowsIdentity.GetCurrent(),
Children = new List<TestData>() { new TestData() { Name = "Doe", Age = 12 }, new TestData() { Name = "Mat", Age = 9 } }
});
public class TestData
{
[System.Xml.Serialization.XmlIgnore]
public WindowsIdentity id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public List<TestData> Children { get; set; }
}
Customization -existing Log4Net converter
<commandText value="INSERT INTO LogMVC3 ([Date],[Thread],[Level],[Logger],[Message],[StackTrace],[AuditData],[UserName]) VALUES (@log_date, @thread, @log_level, @logger,@Message, @stacktrace,@auditdata,@username)" />
<parameter>
<parameterName value="@stacktrace" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%exception" />
</parameter>
<parameter>
<parameterName value="@username" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%username" />
</parameter>
%appdomain
%date
%exception
%file
%identity //slow
%level
%line
%location
%logger
%method
%message
%newline
%timestamp
%type
%username //slow
%utcdate
These can be used to format message:
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value=" %timestamp [%thread] %-5level %logger{2} %ndc - %message%newline" />
</parameter>
Thursday, June 28, 2012
MVC3 Log4Net Async and Customized Logging
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment