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