When we write a program, we will record some logs during the program running. log4net, as a durable log component, is worthy of our trust. In small and medium-sized companies, there is often no professional log server to handle the logs generated by the application program, and the poorly formatted log file makes it difficult to count, analyze and find the logs after going online.
As a common office software, Excel can handle some small and medium-sized data easily. If the log output from log4net can be directly imported into excel, isn't it much faster to query and analyze it?
There are many ways to achieve this function. The advantage of csv is that its file format is relatively simple, it can be opened with any text editor, and it is more convenient to parse. The effect is as follows:
To create a new console program and reference the log4net class library, we need to add four class files: CsvTextWriter, NewFieldConverter, EndRowConverter and CsvPatternLayout.
CsvTextWriter.cs
1 using System.IO; 2 using System.Text; 3 4 namespace CoderBusy.Log4Net.Layout 5 { 6 public class CsvTextWriter : TextWriter 7 { 8 private readonly TextWriter _textWriter; 9 10 public CsvTextWriter(TextWriter textWriter) 11 { 12 _textWriter = textWriter; 13 } 14 15 public override Encoding Encoding => _textWriter.Encoding; 16 17 public override void Write(char value) 18 { 19 _textWriter.Write(value); 20 if (value == '"') 21 _textWriter.Write(value); 22 } 23 24 public void WriteQuote() 25 { 26 _textWriter.Write('"'); 27 } 28 } 29 }
NewFieldConverter.cs
1 using System.IO; 2 using log4net.Util; 3 4 namespace CoderBusy.Log4Net.Layout 5 { 6 public class NewFieldConverter : PatternConverter 7 { 8 protected override void Convert(TextWriter writer, object state) 9 { 10 var ctw = writer as CsvTextWriter; 11 ctw?.WriteQuote(); 12 13 writer.Write(','); 14 15 ctw?.WriteQuote(); 16 } 17 } 18 }
EndRowConverter.cs
1 using System.IO; 2 using log4net.Util; 3 4 namespace CoderBusy.Log4Net.Layout 5 { 6 public class EndRowConverter : PatternConverter 7 { 8 protected override void Convert(TextWriter writer, object state) 9 { 10 var ctw = writer as CsvTextWriter; 11 12 ctw?.WriteQuote(); 13 14 writer.WriteLine(); 15 } 16 } 17 }
CsvPatternLayout.cs
1 using System.IO; 2 using log4net.Core; 3 using log4net.Layout; 4 5 namespace CoderBusy.Log4Net.Layout 6 { 7 public class CsvPatternLayout : PatternLayout 8 { 9 public override void ActivateOptions() 10 { 11 AddConverter("newfield", typeof(NewFieldConverter)); 12 AddConverter("endrow", typeof(EndRowConverter)); 13 base.ActivateOptions(); 14 } 15 16 public override void Format(TextWriter writer, LoggingEvent loggingEvent) 17 { 18 var ctw = new CsvTextWriter(writer); 19 ctw.WriteQuote(); 20 base.Format(ctw, loggingEvent); 21 } 22 } 23 }
When writing the log4net configuration file, just set the layout of the appender to CoderBusy.Log4Net.Layout.CsvPatternLayout , and set the log header. The log format is OK. Note that a newline character needs to be written after the header,% newfield represents the field separator, and endrow represents the end of a line.
<layout type="CoderBusy.Log4Net.Layout.CsvPatternLayout,CoderBusy.Log4Net"> <header value="Time,Thread,Level,Logger,Message,Exception " /> <conversionPattern value="%date{yyyy-MM-dd HH:mm:ss}%newfield%thread%newfield%level%newfield%logger%newfield%message%newfield%exception%endrow" /> </layout>
I prepared a log4net configuration file for beginners. This configuration file will output logs in the console and CSV files at the same time, one CSV file per day (local time), and different log levels in the console will have different colors.
1 <?xml version="1.0" encoding="utf-8"?> 2 3 <configuration> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> 6 </configSections> 7 <log4net xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 8 <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> 9 <param name="File" value="Logs/" /> 10 <param name="AppendToFile" value="True" /> 11 <param name="MaxSizeRollBackups" value="10" /> 12 <param name="StaticLogFileName" value="false" /> 13 <param name="DatePattern" value="yyyy-MM-dd".csv"" /> 14 <param name="RollingStyle" value="Date" /> 15 <layout type="CoderBusy.Log4Net.Layout.CsvPatternLayout,CoderBusy.Log4Net"> 16 <header value="Time,Thread,Level,Logger,Message,Exception " /> 17 <conversionPattern 18 value="%date{yyyy-MM-dd HH:mm:ss}%newfield%thread%newfield%level%newfield%logger%newfield%message%newfield%exception%endrow" /> 19 </layout> 20 </appender> 21 22 <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> 23 <mapping> 24 <level value="ERROR" /> 25 <foreColor value="Red" /> 26 </mapping> 27 <mapping> 28 <level value="INFO" /> 29 <foreColor value="Green" /> 30 </mapping> 31 32 <layout type="log4net.Layout.PatternLayout"> 33 <conversionPattern value="# %date{HH:mm:ss} [%thread] %-5level %logger #%newline%message%newline" /> 34 </layout> 35 <filter type="log4net.Filter.LevelRangeFilter"> 36 <param name="LevelMin" value="DEBUG" /> 37 <param name="LevelMax" value="FATAL" /> 38 </filter> 39 </appender> 40 41 <root> 42 <!-- OFF < FATAL < ERROR < WARN < INFO < DEBUG < ALL --> 43 <level value="ALL" /> 44 <appender-ref ref="RollingLogFileAppender" /> 45 <appender-ref ref="ColoredConsoleAppender" /> 46 </root> 47 </log4net> 48 </configuration>
With the above configuration, test the function.
1 using System; 2 using log4net; 3 using log4net.Config; 4 5 [assembly: XmlConfigurator(ConfigFile = "log4net.config")] 6 7 namespace CoderBusy.Log4Net.Tests 8 { 9 internal class Program 10 { 11 public static void Main(string[] args) 12 { 13 var log = LogManager.GetLogger("Default"); 14 log.Debug("Message", new Exception("Test Exception")); 15 log.Info("Hello World."); 16 log.WarnFormat("A={0} B={1}", "\"123123", Environment.NewLine); 17 Console.ReadLine(); 18 } 19 } 20 }
In the Logs folder, the generated csv file contents are as follows:
Time,Thread,Level,Logger,Message,Exception
"2016-08-25 23:13:19","9","DEBUG","Default","Message","System.Exception: Test Exception
"
"2016-08-25 23:13:19","9","INFO","Default","Hello World.",""
"2016-08-25 23:13:19","9","WARN","Default","A=""123123 B=
",""
The output field is wrapped in double quotes, and the double quotes in the message body are output repeatedly. This result shows that our program is normal. The code in this article can be found in http://pan.baidu.com/s/1hr4EOPu Download, thank you for reading, and I wish you success.