C#-多線程日志Helper


1、原單線程日志

/**
*┌──────────────────────────────────────────────────────────────┐
*│ 描    述:日志相關的工具類                                                   
*│ 作    者:執筆小白                                              
*│ 版    本:1.0                                       
*│ 創建時間:2020-6-13 15:40:56                            
*└──────────────────────────────────────────────────────────────┘
*┌──────────────────────────────────────────────────────────────┐
*│ 命名空間: WMSTOMESTT                               
*│ 類    名:ETools                                     
*└──────────────────────────────────────────────────────────────┘
*/
using System;
using System.IO;
using System.Text;

namespace HOST_CONTROL_CENTER.Uril.LogHelper
{
    public  class LogHelper
    {
        // 寫日志-不支持多線程
        public static void WriteLogFile(string input, string logfilePath)
        {
            try
            {
                // exe的目錄,web的請用:System.Web.Hosting.HostingEnvironment
                // string logAdress = System.Environment.CurrentDirectory.ToString() + "\\Log\\";  // exe.config
                // string logAdress = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase.ToString() + "\\Log\\";  // dll.config

                string[] logfilePaths= logfilePath.Split('\\');
                string logfileName = logfilePaths[logfilePaths.Length-1];  // 文件名
                string logAdress = logfilePath.Replace(logfileName, "");   // 文件目錄

                if (!System.IO.Directory.Exists(logAdress))
                {
                    System.IO.Directory.CreateDirectory(logAdress);//不存在就創建目錄   
                }

                if (!System.IO.Directory.Exists(logAdress))
                {
                    System.IO.Directory.CreateDirectory(logAdress);//不存在就創建目錄   
                }

                ///定義文件信息對象
                FileInfo finfo = new FileInfo(logfilePath);

                if (!finfo.Exists)
                {
                    FileStream fs;
                    fs = File.Create(logfilePath);
                    fs.Close();
                    finfo = new FileInfo(logfilePath);
                }

                ///判斷文件是否存在以及是否大於2K
                if (finfo.Length > 1024 * 1024 * 10)
                {
                    /**/
                    ///文件超過10MB則重命名
                    File.Move(logfilePath, logAdress + DateTime.Now.TimeOfDay + @"\" + logfileName);
                    /**/
                    ///刪除該文件
                    //finfo.Delete();
                }
                //finfo.AppendText();
                /**/
                ///創建只寫文件流
                using (FileStream fs = finfo.OpenWrite())
                {
                    /**/
                    ///根據上面創建的文件流創建寫數據流
                    StreamWriter w = new StreamWriter(fs, Encoding.UTF8);

                    /**/
                    ///設置寫數據流的起始位置為文件流的末尾
                    w.BaseStream.Seek(0, SeekOrigin.End);
                    w.WriteLine(" ");
                    w.WriteLine("---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "----Start----------------------");
                    /**/
                    ///寫入當前系統時間並換行

                    /**/
                    ///寫入日志內容並換行
                    w.WriteLine(input);

                    /**/
                    ///寫入------------------------------------“並換行
                    w.WriteLine("------------------------End------------------------");

                    /**/
                    ///清空緩沖區內容,並把緩沖區內容寫入基礎流
                    w.Flush();

                    /**/
                    ///關閉寫數據流
                    w.Close();
                }
            }
            catch (Exception ex)
            { throw ex; }
        }
    }
    #region 例子
    public class ETest
    {
        public void WLogDemo()
        {
            StringBuilder strHead = new StringBuilder();
            strHead.AppendLine("*****記錄*****");
            LogHelper.WriteLogFile(strHead.ToString(), "記錄文件名");
        }
    }
    #endregion
}

2、日志信息對象類

namespace HOST_CONTROL_CENTER.Uril.LogHelper.LogThreed
{
    /// <summary>
    /// 日志信息對象類(用於在線程間共享)
    /// </summary>
    public class LogInfo
    {
        private int _ID;
        /// <summary>
        /// 日志ID
        /// </summary>
        public int ID
        {
            get { return _ID; }
            set { _ID = value; }
        }

        private string _CreateTime;
        /// <summary>
        /// 日志時間
        /// </summary>
        public string CreateTime
        {
            get { return _CreateTime; }
            set { _CreateTime = value; }
        }

        private string _Content;
        /// <summary>
        /// 日志內容
        /// </summary>
        public string Content
        {
            get { return _Content; }
            set { _Content = value; }
        }

        private string _LogPath;
        /// <summary>
        /// 日志保存位置
        /// </summary>
        public string LogPath
        {
            get { return _LogPath; }
            set { _LogPath = value; }
        }
    }
}

3、日志-同步事件類(用於線程間同步的事件對象)

using System.Threading;

namespace HOST_CONTROL_CENTER.Uril.LogHelper.LogThreed
{
    /// <summary>
    /// 日志-同步事件類(用於線程間同步的事件對象)
    /// </summary>
    public class SyncEvents
    {
        private EventWaitHandle _newItemEvent;      // 添加新項
        private EventWaitHandle _exitThreadEvent;   // 退出線程
        private WaitHandle[] _eventArray;           // 線程組

        /// <summary>
        /// 構造器
        /// </summary>
        public SyncEvents()
        {
            _newItemEvent = new AutoResetEvent(false);       // AutoResetEvent對象用來進行線程同步操作(表示線程同步事件在一個等待線程釋放后收到信號時自動重置)
            _exitThreadEvent = new ManualResetEvent(false);  // ManualResetEvent是線程用來控制別一個線程的信號事件(表示線程同步事件中,收到信號時,必須手動重置該事件。 此類不能被繼承。)
            _eventArray = new WaitHandle[2];
            _eventArray[0] = _newItemEvent;
            _eventArray[1] = _exitThreadEvent;
        }
        /// <summary>
        /// 獲取要退出的線程
        /// </summary>
        public EventWaitHandle ExitThreadEvent
        {
            get { return _exitThreadEvent; }
        }
        /// <summary>
        /// 獲取新添加的項
        /// </summary>
        public EventWaitHandle NewItemEvent
        {
            get { return _newItemEvent; }
        }
        /// <summary>
        /// 獲取線程組
        /// </summary>
        public WaitHandle[] EventArray
        {
            get { return _eventArray; }
        }
    }
}

4、日志記錄類-支持多線程

using System.Threading;
using System.Collections.Generic;
using System;
using System.Collections;

namespace HOST_CONTROL_CENTER.Uril.LogHelper.LogThreed
{
    /// <summary>
    /// 日志記錄類-支持多線程
    /// </summary>
    public class Logger
    {
        private static Logger _logger;
        private static object _lock = new object();  // 鎖
        private static Thread _thread;  // 線程
        
        private Queue<LogInfo> _queue;   //日志隊列
        private SyncEvents _syncEvents;  // 線程同步事件

        /// <summary>
        /// 構造器
        /// </summary>
        private Logger()
        {
            _queue = new Queue<LogInfo>();
            _syncEvents = new SyncEvents();
        }

        /// <summary>
        /// 獲取日志記錄類實例
        /// </summary>
        /// <returns></returns>
        public static Logger GetLogger()
        {
            if (_logger == null)
            {
                // 加鎖,防止多線程運行時,重復創建。
                lock (_lock)
                {
                    if (_logger == null)
                    {
                        _logger = new Logger();
                    }
                }
            }

            return _logger;
        }

        #region 添加日志
        private void AddLog(Object obj)
        {
            LogInfo log = obj as LogInfo;
            if (!_syncEvents.ExitThreadEvent.WaitOne(0, false))  // 首先檢查“退出線程”事件,因為 WaitOne 使用的第一個參數為零,該方法會立即返回,所以檢查該事件的狀態不會阻止當前線程。
            {
                lock (((ICollection)_queue).SyncRoot)
                {
                    _queue.Enqueue(log);
                    _syncEvents.NewItemEvent.Set();  // 添加新項(啟動一個新線程運行AddLog方法向共享隊列中添加新日志)
                    Console.WriteLine("Input thread: add {0} items", log.ID);
                }
            }
        }

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="log"></param>
        public void Add(LogInfo log)
        {
            Thread t = new Thread(AddLog);
            t.Start(log);
        }
        #endregion

        #region 輸出日志
        /// <summary>
        /// 日志保存
        /// </summary>
        private void Save()
        {
            int flag = 0;
            while (flag >= 0)    // 處理完所有線程時退出
            {
                if (_queue.Count == 0)
                {
                    flag = WaitHandle.WaitAny(_syncEvents.EventArray);
                    if (flag == 1)
                    {
                        flag = -1;
                    }
                }
                lock (((ICollection)_queue).SyncRoot)
                {
                    if (_queue.Count > 0)
                    {
                        LogInfo log = _queue.Dequeue();    // 移除隊列
                        Console.WriteLine("Output Thread: process {0} items,{1}", log.ID,log.Content);

                        LogHelper.WriteLogFile(log.Content, log.LogPath);  // 保存到文件
                    }
                }
            }
        }
        public void Run()
        {
            _thread = new Thread(Save);
            _thread.Start();
        }
        #endregion

        /// <summary>
        /// 退出所有正在使用的線程
        /// </summary>
        public void Stop()
        {
            _syncEvents.ExitThreadEvent.Set();
        }
    }
}

  覺得不需要,所以未對文件加鎖。

5、添加的一個日志格式擴展類,作為使用參考(可以改成自己的)

using System;

namespace HOST_CONTROL_CENTER.Uril.LogHelper.LogThreed
{
    public class AppLogs
    {
        // 本地MES的常規報錯日志的保存地址
        private static string _MesLogPath = System.Environment.CurrentDirectory.ToString();
        // MES接口日志
        private static string _MesAPILogPath = @"D:\MESlog\MES\";
        // 工序日志
        private static string _MESDataLogPath = @"D:\MESData\MES\";

        /// <summary>
        /// 常規報錯日志
        /// </summary>
        public static void MesLog(string msgContent)
        {
            Logger logger = Logger.GetLogger();
            logger.Run();
            for (int i = 0; i < 1; i++)
            {
                LogInfo log = new LogInfo();
                log.LogPath = _MesLogPath + @"\Log\" + DateTime.Now.ToString("yyyy-MM-dd") + ".csv";
                log.ID = 1;
                log.CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.SSS");
                log.Content = msgContent;
                logger.Add(log);

                if (i == 1)
                {
                    logger.Stop();
                }
            }
        }

        /// <summary>
        /// MES接口日志
        /// D:\MESlog\接口名\設備號_log_年-月-日;
        /// </summary>
        /// <param name="aPIName">接口名_操作名</param>
        /// <param name="deviceNumber">設備號</param>
        /// <param name="msgContent">消息內容</param>
        public static void MesAPILog(string aPIName, string deviceNumber, string msgContent)
        {
            string iniPath = System.Environment.CurrentDirectory.ToString() + @"\MESConfig.ini";
            //_MesAPILogPath = OperateFile_InI.ReadIniData("Log", "MesAPILogPath", "", iniPath);

            Logger logger = Logger.GetLogger();
            logger.Run();
            for (int i = 0; i < 1; i++)
            {
                LogInfo log = new LogInfo();
                log.ID = 1;
                log.CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.SSS");
                log.LogPath = _MesAPILogPath + aPIName + @"\" + deviceNumber + "_log_" + DateTime.Now.ToString("yyyy-MM-dd") + ".csv";
                log.Content = msgContent;
                logger.Add(log);

                if (i == 1)
                {
                    logger.Stop();
                }
            }
        }

        /// <summary>
        /// 工序日志
        /// 如:D:\MESData\MES\SFC\12B000000001_20150826105626.csv
        /// </summary>
        /// <param name="sFCName">SFC名</param>
        /// <param name="deviceNumber">設備號</param>
        /// <param name="msgContent">消息內容</param>
        public static void MESDataLog(string sFCName, string deviceNumber, string msgContent)
        {
            // 獲取
            string iniPath = System.Environment.CurrentDirectory.ToString() + @"\MESConfig.ini";
            //_MESDataLogPath = OperateFile_InI.ReadIniData("Log", "MESDataLogPath", "", iniPath);
            
            Logger logger = Logger.GetLogger();
            logger.Run();

            for (int i = 0; i < 1; i++)
            {
                LogInfo log = new LogInfo();
                log.ID = 1;
                log.CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.SSS");
                log.LogPath = _MESDataLogPath + sFCName + @"\" + deviceNumber + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv";
                log.Content = msgContent;
                logger.Add(log);

                if (i == 1)
                {
                    logger.Stop();
                }
            }
        }
    }
}

參考:支持多線程的日志記錄類實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM