0

0

log4Net 高性能写入和CSV格式的实例详解

Y2J

Y2J

发布时间:2017-04-25 09:21:43

|

3317人浏览过

|

来源于php中文网

原创

最近在使用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 有多个工作者) 如:   

但是这里的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
    {        /// 
        /// 记录消息Queue        /// 
        private readonly ConcurrentQueue _que;        /// 
        /// 信号        /// 
        private readonly ManualResetEvent _mre;        /// 
        /// 日志        /// 
        private readonly ILog _log;        /// 
        /// 日志        /// 
        private static QueueLogger flashLog = new QueueLogger();        private QueueLogger()
        {            // 设置日志配置文件路径            //XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config")));
            _que = new ConcurrentQueue();
            _mre = new ManualResetEvent(false);
            _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            Task.Run(() => { WriteLog(); });
        }        /// 
        /// 从队列中写日志至磁盘        /// 
        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();
            }
        }        /// 
        /// 写日志        /// 
        /// 日志文本
        /// 等级
        /// Exception
        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);
        }
    }    /// 
    /// 日志等级    /// 
    public enum QueueLogLevel
    {
        Debug,
        Info,
        Error,
        Warn,
        Fatal
    }    /// 
    /// 日志内容    /// 
    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();
        }
    }
}

配置文件中需要加上逗号


这里 是\r\n,%newfield是一个逗号,%endrow是逗号+换行

看到这里其实我们可以自己拼接CSV的内容,也就是说只要有,\r\n就可以了


调用code:

StringBuilder sb = new StringBuilder();
sb.Append("test");
sb.Append("\",\"");
sb.Append("debug");
QueueLogger.Debug(sb.ToString());

写入的信息是test","debug,在加上ConversionPattern里面的配置就是"test","debug".整个配置如下:



  
    

 

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

4

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

2

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

1

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

1

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

16

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

18

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

3

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.9万人学习

C 教程
C 教程

共75课时 | 4.3万人学习

C++教程
C++教程

共115课时 | 14.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号