欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

可替代log4j日志的c#简单日志类队列实现类代码分享

程序员文章站 2024-02-19 21:46:16
复制代码 代码如下:using system;using system.collections.generic;using system.globalization;usi...

复制代码 代码如下:

using system;
using system.collections.generic;
using system.globalization;
using system.io;
using system.linq;
using system.text;
using system.threading;

namespace logistrac
{
    /// <summary>
    /// 日志类
    /// 队列 可年/月/周/日/大小分割
    /// 调用方法:
    ///  log.instance.logdirectory=@"c:\"; 默认为程序运行目录
    ///  log.instance.filenameprefix="cxd";默认为log_
    ///  log.instance.currentmsgtype = msglevel.debug;默认为error
    ///  log.instance.logfilesplit = logfilesplit.daily; 日志拆分类型logfilesplit.sizely 大小
    ///  log.instance.maxfilesize = 5; 默认大小为2m,只有logfilesplit.sizely的时候配置有效
    ///  log.instance.logwrite("aa");
    ///  log.instance.logwrite("aa", msglevel.debug);
    /// </summary>
    public class log : idisposable
    {
        private static log _instance = null;
        private static readonly object _synobject = new object();

        /// <summary>
        ///单例
        /// </summary>
        public static log instance
        {
            get
            {
                if (null == _instance)
                {
                    lock (_synobject)
                    {
                        if (null == _instance)
                        {
                            _instance = new log();
                        }
                    }
                }
                return _instance;
            }
        }

        /// <summary>
        /// 日志对象的缓存队列
        /// </summary>
        private static queue<msg> _msgs;

        /// <summary>
        /// 日志写入线程的控制标记  ture写中|false没有写
        /// </summary>
        private  bool _state;

        private  string _logdirectory = appdomain.currentdomain.basedirectory;

        /// <summary>
        /// 日志文件存放目录
        /// </summary>
        public  string logdirectory
        {
            get { return _logdirectory; }
            set { _logdirectory = value; }
        }

        private  logfilesplit _logfilesplit = logfilesplit.sizely;
        /// <summary>
        /// 日志拆分类型
        /// </summary>
        public  logfilesplit logfilesplit
        {
            get { return _logfilesplit; }
            set { _logfilesplit = value; }
        }

        private msglevel _currentloglevel = msglevel.error;

        /// <summary>
        /// 当前日志记录等级
        /// </summary>
        public msglevel currentmsgtype
        {
            get { return _currentloglevel; }
            set { _currentloglevel = value; }
        }

        /// <summary>
        /// 当前负责记录日志文件的名称
        /// </summary>
        private  string _currentfilename="1.log";

        private  string _filenameprefix = "log_";

        /// <summary>
        /// 日志的前缀名称,默认为log_
        /// </summary>
        public string filenameprefix
        {
            get { return _filenameprefix; }
            set { _filenameprefix = value; }
        }

        /// <summary>
        /// 日志文件生命周期的时间标记
        /// </summary>
        private  datetime _currentfiletimesign = new datetime();

        private  int _maxfilesize = 2;

        /// <summary>
        /// 单个日志文件默认大小(单位:兆)
        /// </summary>
        public  int maxfilesize
        {
            get { return _maxfilesize; }
            set { _maxfilesize = value; }
        }

        /// <summary>
        /// 文件后缀号
        /// </summary>
        private  int _filesymbol = 0;


        /// <summary>
        /// 当前文件大小(单位:b)
        /// </summary>
        private  long _filesize = 0;

        /// <summary>
        /// 日志文件写入流对象
        /// </summary>
        private streamwriter _writer;


        /// <summary>
        /// 创建日志对象的新实例,根据指定的日志文件路径和指定的日志文件创建类型
        /// </summary>
        private log()
        {
            if (_msgs == null)
            {
                getcurrentfilename();
                _state = true;
                _msgs = new queue<msg>();
                thread thread = new thread(work);
                thread.start();
            }
        }

        //日志文件写入线程执行的方法
        private void work()
        {
            while (true)
            {
                //判断队列中是否存在待写入的日志
                if (_msgs.count > 0)
                {
                    msg msg = null;
                    lock (_msgs)
                    {
                        msg = _msgs.dequeue();

                        if (msg != null)
                        {
                            filewrite(msg);
                        }
                    }
                }
                else
                {
                    //判断是否已经发出终止日志并关闭的消息
                    if (_state)
                    {
                        thread.sleep(1);
                    }
                    else
                    {
                        fileclose();
                    }
                }
            }
        }

        /// <summary>
        /// 根据日志类型获取日志文件名,并同时创建文件到期的时间标记
        /// 通过判断文件的到期时间标记将决定是否创建新文件。
        /// </summary>
        /// <returns></returns>
        private
            void  getcurrentfilename()
        {
            datetime now = datetime.now;
            string format = "";
            switch (_logfilesplit)
            {
                case logfilesplit.daily:
                    _currentfiletimesign = new datetime(now.year, now.month, now.day);
                    _currentfiletimesign = _currentfiletimesign.adddays(1);
                    format = now.tostring("yyyymmdd'.log'");
                    break;
                case logfilesplit.weekly:
                    _currentfiletimesign = new datetime(now.year, now.month, now.day);
                    _currentfiletimesign = _currentfiletimesign.adddays(7);
                    format = now.tostring("yyyymmdd'.log'");
                    break;
                case logfilesplit.monthly:
                    _currentfiletimesign = new datetime(now.year, now.month, 1);
                    _currentfiletimesign = _currentfiletimesign.addmonths(1);
                    format = now.tostring("yyyymm'.log'");
                    break;
                case logfilesplit.annually:
                    _currentfiletimesign = new datetime(now.year, 1, 1);
                    _currentfiletimesign = _currentfiletimesign.addyears(1);
                    format = now.tostring("yyyy'.log'");
                    break;
                default:
                    _filesymbol++;
                    format = _filesymbol.tostring() + ".log";
                    break;
            }
            if (file.exists(path.combine(logdirectory, _currentfilename)))
            {
                _filesize = new fileinfo(path.combine(logdirectory, _currentfilename)).length;
            }
            else
            {
                _filesize = 0;
            }
            _currentfilename=_filenameprefix + format.trim();
        }

        //写入日志文本到文件的方法
        private void filewrite(msg msg)
        {
            try
            {
                if (_writer == null)
                {
                    fileopen();

                }

                if (_writer != null)
                {
                    //判断文件到期标志,如果当前文件到期则关闭当前文件创建新的日志文件
                    if ((_logfilesplit != logfilesplit.sizely && datetime.now >= _currentfiletimesign)||
                        (_logfilesplit == logfilesplit.sizely && ((double)_filesize / 1048576) > _maxfilesize))
                    {
                        getcurrentfilename();
                        fileclose();
                        fileopen();
                    }
                    _writer.write(msg.datetime);
                    _writer.write('\t');
                    _writer.write(msg.type);
                    _writer.write('\t');
                    _writer.writeline(msg.text);                   
                    _filesize+=system.text.encoding.utf8.getbytes(msg.tostring()).length;  
                    _writer.flush();
                }
            }
            catch (exception e)
            {
                console.out.write(e);
            }
        }

        //打开文件准备写入
        private void fileopen()
        {
            _writer = new streamwriter(logdirectory + _currentfilename, true, encoding.utf8);
        }

        //关闭打开的日志文件
        private void fileclose()
        {
            if (_writer != null)
            {
                _writer.flush();
                _writer.close();
                _writer.dispose();
                _writer = null;
            }
        }

        /// <summary>
        /// 写入新日志,根据指定的日志对象msg
        /// </summary>
        /// <param name="msg">日志内容对象</param>
        private void logwrite(msg msg)
        {
            if (msg.type < currentmsgtype)
                return;
            if (_msgs != null)
            {
                lock (_msgs)
                {
                    _msgs.enqueue(msg);
                }
            }
        }

        /// <summary>
        /// 写入新日志,根据指定的日志内容和信息类型,采用当前时间为日志时间写入新日志
        /// </summary>
        /// <param name="text">日志内容</param>
        /// <param name="type">信息类型</param>
        public void logwrite(string text, msglevel type)
        {
            logwrite(new msg(text, type));
        }

        /// <summary>
        /// 写入新日志,根据指定的日志内容
        /// </summary>
        /// <param name="text">日志内容</param>
        public void logwrite(string text)
        {
            logwrite(text, msglevel.debug);
        }

        /// <summary>
        /// 写入新日志,根据指定的日志时间、日志内容和信息类型写入新日志
        /// </summary>
        /// <param name="dt">日志时间</param>
        /// <param name="text">日志内容</param>
        /// <param name="type">信息类型</param>
        public void logwrite(datetime dt, string text, msglevel type)
        {
            logwrite(new msg(dt, text, type));
        }

        /// <summary>
        /// 写入新日志,根据指定的异常类和信息类型写入新日志
        /// </summary>
        /// <param name="e">异常对象</param>
        /// <param name="type">信息类型</param>
        public void logwrite(exception e)
        {
            logwrite(new msg(e.message, msglevel.error));
        }

        /// <summary>
        /// 销毁日志对象
        /// </summary>
        public void dispose()
        {
            _state = false;
        }
    }


    /// <summary>
    /// 一个日志记录的对象
    /// </summary>
    public class msg
    {

        /// <summary>
        /// 创建新的日志记录实例;日志记录的内容为空,消息类型为msgtype.unknown,日志时间为当前时间
        /// </summary>
        public msg()
            : this("", msglevel.debug)
        {
        }

        /// <summary>
        /// 创建新的日志记录实例;日志事件为当前时间
        /// </summary>
        /// <param name="t">日志记录的文本内容</param>
        /// <param name="p">日志记录的消息类型</param>
        public msg(string t, msglevel p)
            : this(datetime.now, t, p)
        {
        }

        /// <summary>
        /// 创建新的日志记录实例;
        /// </summary>
        /// <param name="dt">日志记录的时间</param>
        /// <param name="t">日志记录的文本内容</param>
        /// <param name="p">日志记录的消息类型</param>
        public msg(datetime dt, string t, msglevel p)
        {
            datetime = dt;
            type = p;
            text = t;
        }

        /// <summary>
        /// 日志记录的时间
        /// </summary>
        public datetime datetime { get; set; }

        /// <summary>
        ///日志记录的内容
        /// </summary>
        public string text { get; set; }

        /// <summary>
        /// 日志等级
        /// </summary>
        public msglevel type { get; set; }


        public new string tostring()
        {
            return datetime.tostring(cultureinfo.invariantculture) + "\t" + text + "\n";
        }
    }

    /// <summary>
    /// 日志文件拆分的枚举
    /// </summary>
    /// <remarks>日志类型枚举指示日志文件创建的方式,如果日志比较多可考虑每天创建一个日志文件
    /// 如果日志量比较小可考虑每周、每月或每年创建一个日志文件</remarks>
    public enum logfilesplit
    {
        /// <summary>
        /// 此枚举指示每天创建一个新的日志文件
        /// </summary>
        daily,

        /// <summary>
        /// 此枚举指示每周创建一个新的日志文件
        /// </summary>
        weekly,

        /// <summary>
        /// 此枚举指示每月创建一个新的日志文件
        /// </summary>
        monthly,

        /// <summary>
        /// 此枚举指示每年创建一个新的日志文件
        /// </summary>
        annually,

        /// <summary>
        /// 日志文件大小超过指定的创建一个新的日志文件,maxfilesize指定大小
        /// </summary>
        sizely
    }

    /// <summary>
    /// 日志等级类型 debug=0 infor warn error
    /// </summary>
    public enum msglevel
    {
        /// <summary>
        /// 调试信息
        /// </summary>
        debug = 0,

        /// <summary>
        /// 指示普通信息类型的日志记录
        /// </summary>
        infor,

        /// <summary>
        /// 指示警告信息类型的日志记录
        /// </summary>
        warn,

        /// <summary>
        /// 指示错误信息类型的日志记录
        /// </summary>
        error
    }

}