[C#]简易日志记录,线程安全

11/25/2015来源:ASP.NET技巧人气:1254

在实际项目开发中,会涉及日志记录问题,比较常用的有Log4Net,NLog等几个,而小项目小工具的话,则无需费此大驾。而譬如串口开发的话,需要记录串口过来的数据等等,则需要考虑日志记录上线程的问题,为了方便后续使用,封装了下代码,如下:

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace CSharpUtilHelpV2
{
    /// <summary>
    /// 日志类型枚举
    /// </summary>
    public enum LogType
    {
        /// <summary>
        /// 一般输出
        /// </summary>
        Trace,
        /// <summary>
        /// 警告
        /// </summary>
        Warning,
        /// <summary>
        /// 错误
        /// </summary>
        Error,
        /// <summary>
        /// SQL
        /// </summary>
        SQL
    }
    /// <summary>
    /// 基于.NET 2.0日志工具类
    /// </summary>
    public class LogToolV2
    {
        PRivate static readonly Thread LogTask;
        private static readonly ThreadSafeQueueV2<string> LogColQueue;//自定义线程安全的Queue
        private static readonly object SyncRoot;
        private static readonly string FilePath;
        private static readonly long BackFileSize_MB = 2;//超过2M就开始备份日志文件
        static LogToolV2()
        {
            SyncRoot = new object();
            FilePath = AppDomain.CurrentDomain.SetupInformation.applicationBase + "Log\\";
            LogTask = new Thread(WriteLog);
            LogColQueue = new ThreadSafeQueueV2<string>();
            LogTask.Start();
            Debug.WriteLine("Log Start......");
        }
        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="msg">日志内容</param>
        public static void Log(string msg)
        {
            string _msg = string.Format("{0} : {2}", DateTime.Now.ToString("HH:mm:ss"), msg);
            LogColQueue.Enqueue(msg);
        }
        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="msg">日志内容</param>
        /// <param name="type">日志类型</param>
        public static void Log(string msg, LogType type)
        {
            string _msg = string.Format("{0} {1}: {2}", DateTime.Now.ToString("HH:mm:ss"), type, msg);
            LogColQueue.Enqueue(_msg);
        }
        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="ex">异常</param>
        public static void Log(Exception ex)
        {
            if (ex != null)
            {
                string _newLine = Environment.NewLine;
                StringBuilder _builder = new StringBuilder();
                _builder.AppendFormat("{0}: {1}{2}", DateTime.Now.ToString("HH:mm:ss"), ex.Message, _newLine);
                _builder.AppendFormat("{0}{1}", ex.GetType(), _newLine);
                _builder.AppendFormat("{0}{1}", ex.Source, _newLine);
                _builder.AppendFormat("{0}{1}", ex.TargetSite, _newLine);
                _builder.AppendFormat("{0}{1}", ex.StackTrace, _newLine);
                LogColQueue.Enqueue(_builder.ToString());
            }
        }
        private static void WriteLog()
        {
            while (true)
            {
                if (LogColQueue.Count() > 0)
                {
                    string _msg = LogColQueue.Dequeue();
                    Monitor.Enter(SyncRoot);
                    if (!CreateDirectory()) continue;
                    string _path = string.Format("{0}{1}.log", FilePath, DateTime.Now.ToString("yyyyMMdd"));
                    Monitor.Exit(SyncRoot);
                    lock (SyncRoot)
                    {
                        if (CreateFile(_path))
                            ProcessWriteLog(_path, _msg);//写入日志到文本
                    }
                    ProcessBackLog(_path);//日志备份
                }
            }
        }
        private static void ProcessBackLog(string path)
        {
            lock (SyncRoot)
            {
                if (FileToolV2.GetMBSize(path) > BackFileSize_MB)
                {
                    FileToolV2.CopyToBak(path);
                }
            }
        }
        private static void ProcessWriteLog(string path, string msg)
        {
            try
            {
                StreamWriter _sw = File.AppendText(path);
                _sw.WriteLine(msg);
                _sw.Flush();
                _sw.Close();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(string.Format("写入日志失败,原因:{0}", ex.Message));
            }
        }
        private static bool CreateFile(string path)
        {
            bool _result = true;
            try
            {
                if (!File.Exists(path))
                {
                    FileStream _files = File.Create(path);
                    _files.Close();
                }
            }
            catch (Exception)
            {
                _result = false;
            }
            return _result;
        }
        private static bool CreateDirectory()
        {
            bool _result = true;
            try
            {
                if (!Directory.Exists(FilePath))
                {
                    Directory.CreateDirectory(FilePath);
                }
            }
            catch (Exception)
            {
                _result = false;
            }
            return _result;
        }

    }
}

测试代码:

using CSharpUtilHelpV2;
using System;
using System.Diagnostics;
using System.Threading;

namespace LogUtilHelpV2Test
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Debug.WriteLine("-------------");
                Action _writeLog = delegate()
                {
                    for (int i = 0; i < 10000; i++)
                        LogToolV2.Log(Guid.NewGuid().ToString(), LogType.Trace);
                };
                Thread _wireteLogTask1 = new Thread(new ThreadStart(_writeLog));
                _wireteLogTask1.Start();

                Thread _wireteLogTask2 = new Thread(new ThreadStart(_writeLog));
                _wireteLogTask2.Start();

                //throw new Exception("test   aaa bb  cc");
            }
            catch (Exception ex)
            {
                LogToolV2.Log(ex);
                Console.WriteLine(ex.Message.Trim());
            }
            finally
            {
                Console.WriteLine("ok");
                Console.ReadLine();
            }
        }
    }
}

代码效果:

image

才疏学浅,如有纰漏,敬请指出,希望有所帮助!谢谢 大笑