您好,登錄后才能下訂單哦!
小編給大家分享一下c#中log4Net高性能寫入和CSV格式的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
最近在使用log4net,在使用之前我們必須知道文件流是如何操作的,否則就是盲人摸向。。。,在FileAppender.cs文件里面有LockingModelBase來控制流的鎖,默認有3個子類
ExclusiveLock:默認的,Hold an exclusive lock on the output file,Open the file once for writing and hold it open until CloseFile is called. Maintains an exclusive lock on the file during this time.
MinimalLock:Acquires the file lock for each write,Opens the file once for each AcquireLock / ReleaseLock cycle, thus holding the lock for the minimal amount of time.This method of locking is considerably slower than FileAppender.ExclusiveLock but allows other processes to move/delete the log file whilst logging continues.
InterProcessLock:Provides cross-process file locking.使用Mutex來實現多進程
這里意思是MinimalLock比ExclusiveLock慢一點,因為它每次都會打開關閉文件流。
不過有2個類感覺比較重要PatternString.cs
和PatternLayout.cs
如果log文件在一個公共的目錄,建議大家log文件加上計算機名稱、應用程序名稱、進程ID(如web 有多個工作者) 如:
<file type="log4net.Util.PatternString" value="\\192.168.0.1\logs\%env{COMPUTERNAME}\%appsetting{ApplicationName}\%processid\Log\" />
但是這里的log記錄默認都是采用同步方式的,但是我個人更趨向用異步多線程的思路來寫log,首先log的信息記錄在內存ConcurrentQueue里面,然后在通過一個后臺線程把ConcurrentQueue里面的東西記錄到文件流里面。至于性能高出多少我想就不用多說了吧,寫內存肯定比寫流快啊
具體實現code如下:
[assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.config")]namespace ConsoleApp { using log4net; using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; public sealed class QueueLogger { /// <summary> /// 記錄消息Queue /// </summary> private readonly ConcurrentQueue<QueueLogMessage> _que; /// <summary> /// 信號 /// </summary> private readonly ManualResetEvent _mre; /// <summary> /// 日志 /// </summary> private readonly ILog _log; /// <summary> /// 日志 /// </summary> private static QueueLogger flashLog = new QueueLogger(); private QueueLogger() { // 設置日志配置文件路徑 //XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config"))); _que = new ConcurrentQueue<QueueLogMessage>(); _mre = new ManualResetEvent(false); _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); Task.Run(() => { WriteLog(); }); } /// <summary> /// 從隊列中寫日志至磁盤 /// </summary> private void WriteLog() { while (true) { // 等待信號通知 _mre.WaitOne(); QueueLogMessage msg; // 判斷是否有內容需要如磁盤 從列隊中獲取內容,并刪除列隊中的內容 while (_que.Count > 0 && _que.TryDequeue(out msg)) { // 判斷日志等級,然后寫日志 switch (msg.Level) { case QueueLogLevel.Debug: _log.Debug(msg.Message, msg.Exception); break; case QueueLogLevel.Info: _log.Info(msg.Message, msg.Exception); break; case QueueLogLevel.Error: _log.Error(msg.Message, msg.Exception); break; case QueueLogLevel.Warn: _log.Warn(msg.Message, msg.Exception); break; case QueueLogLevel.Fatal: _log.Fatal(msg.Message, msg.Exception); break; } } // 重新設置信號 _mre.Reset(); } } /// <summary> /// 寫日志 /// </summary> /// <param name="message">日志文本</param> /// <param name="level">等級</param> /// <param name="ex">Exception</param> public void EnqueueMessage(string message, QueueLogLevel level, Exception ex = null) { if ((level == QueueLogLevel.Debug && _log.IsDebugEnabled) || (level == QueueLogLevel.Error && _log.IsErrorEnabled) || (level == QueueLogLevel.Fatal && _log.IsFatalEnabled) || (level == QueueLogLevel.Info && _log.IsInfoEnabled) || (level == QueueLogLevel.Warn && _log.IsWarnEnabled)) { _que.Enqueue(new QueueLogMessage { // Message = "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff") + "]\r\n" + message, Message = message, Level = level, Exception = ex }); // 通知線程往磁盤中寫日志 _mre.Set(); } } public static void Debug(string msg, Exception ex = null) { flashLog.EnqueueMessage(msg, QueueLogLevel.Debug, ex); } public static void Error(string msg, Exception ex = null) { flashLog.EnqueueMessage(msg, QueueLogLevel.Error, ex); } public static void Fatal(string msg, Exception ex = null) { flashLog.EnqueueMessage(msg, QueueLogLevel.Fatal, ex); } public static void Info(string msg, Exception ex = null) { flashLog.EnqueueMessage(msg, QueueLogLevel.Info, ex); } public static void Warn(string msg, Exception ex = null) { flashLog.EnqueueMessage(msg, QueueLogLevel.Warn, ex); } } /// <summary> /// 日志等級 /// </summary> public enum QueueLogLevel { Debug, Info, Error, Warn, Fatal } /// <summary> /// 日志內容 /// </summary> public class QueueLogMessage { public string Message { get; set; } public QueueLogLevel Level { get; set; } public Exception Exception { get; set; } } }
至于CSV格式有2中方法 實現,一是自定義PatternLayout類:
namespace log4net { using Layout; using System.IO; using System.Text; using Util; using Core; public class CSVPatternLayout : PatternLayout { public override void ActivateOptions() { AddConverter("newfield", typeof(CSVNewFiledConverter)); AddConverter("endrow", typeof(CSVEndRowConverter)); base.ActivateOptions(); } public override void Format(TextWriter writer, LoggingEvent loggingEvent) { var csvWriter = new CSVTextWriter(writer); csvWriter.WriteQuote(); base.Format(csvWriter, loggingEvent); } } public class CSVTextWriter : TextWriter { private readonly TextWriter textWriter; public CSVTextWriter(TextWriter txtWriter) { textWriter = txtWriter; } public override void Write(char value) { // base.Write(value); textWriter.Write(value); //if (value == '"') //{ //} } public void WriteQuote() { textWriter.Write('"'); } public override Encoding Encoding { get { return textWriter.Encoding; } } } public class CSVNewFiledConverter : PatternConverter { protected override void Convert(TextWriter writer, object state) { var csvWriter = writer as CSVTextWriter; csvWriter?.WriteQuote(); writer.Write(","); csvWriter?.WriteQuote(); } } public class CSVEndRowConverter : PatternConverter { protected override void Convert(TextWriter writer, object state) { var csvWriter = writer as CSVTextWriter; csvWriter?.WriteQuote(); writer.WriteLine(); } } }
配置文件中需要加上逗號
<layout type="log4net.CSVPatternLayout,ConsoleApp"> <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>
這里 是\r\n,%newfield是一個逗號,%endrow是逗號+換行
看到這里其實我們可以自己拼接CSV的內容,也就是說只要有,\r\n就可以了
<layout type="log4net.Layout.PatternLayout"> <header value="Time,Message,Type , " /> <param name="ConversionPattern" value=" "%date{yyyy-MM-dd HH:mm:ss}","%message%" "/> </layout>
調用code:
StringBuilder sb = new StringBuilder(); sb.Append("test"); sb.Append("\",\""); sb.Append("debug"); QueueLogger.Debug(sb.ToString());
寫入的信息是test","debug,在加上ConversionPattern里面的配置就是"test","debug".整個配置如下:
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <log4net xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <appender name="InfoLog" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log\Info\Info" /> <param name="AppendToFile" value="True" /> <appendToFile value="true" /> <maxSizeRollBackups value="100" /> <maximumFileSize value="10MB" /> <staticLogFileName value="false" /> <rollingStyle value="Composite" /> <datePattern value="yyyyMMdd'.csv'" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.CSVPatternLayout,ConsoleApp"> <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> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="INFO" /> <param name="LevelMax" value="INFO" /> </filter> </appender> <appender name="DebugLog" type="log4net.Appender.RollingFileAppender"> <file type="log4net.Util.PatternString" value="Log\Debug\Debug" /> <appendToFile value="true" /> <maxSizeRollBackups value="100" /> <maximumFileSize value="10MB" /> <staticLogFileName value="false" /> <rollingStyle value="Composite" /> <datePattern value="yyyyMMdd'.csv'" /> <lockingModel type="log4net.Appender.FileAppender+ExclusiveLock" /> <layout type="log4net.Layout.PatternLayout"> <header value="Time,Message,Type, " /> <param name="ConversionPattern" value=""%date{yyyy-MM-dd HH:mm:ss}","%message%" "/> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="DEBUG" /> </filter> </appender> <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> <mapping> <level value="ERROR" /> <foreColor value="Red" /> </mapping> <mapping> <level value="INFO" /> <foreColor value="Green" /> </mapping> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="# %date{HH:mm:ss} [%thread] %-5level %logger #%newline%message%newline" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="FATAL" /> </filter> </appender> <root> <!-- OFF < FATAL < ERROR < WARN < INFO < DEBUG < ALL --> <level value="ALL" /> <appender-ref ref="InfoLog" /> <appender-ref ref="DebugLog" /> <!-- <appender-ref ref="ColoredConsoleAppender" /> --> </root> </log4net> </configuration>
以上是“c#中log4Net高性能寫入和CSV格式的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。