C# 簡單的日誌系統(服務端)

來源:互聯網
上載者:User

新的一年開始,也該開始學習一些新的東西,首先就是將去年寫的C#伺服器重新構思一下。
今天的目標:日誌系統
需求:
1.顯示日誌
2.寫入到本地檔案
3.錯誤或異常日誌需要通過郵件通知
4.可以自定日誌類型(可有可無)

日誌:
我個人理解,就是系統在運行過程中所產生的提示資訊。比如,Debug程式的時候,除了進行斷點調試,大多都是進行文本輸出,來觀察這一段程式書寫是否正確。其次,就是我們經常碰到的錯誤或者捕獲的異常資訊等。通過觀察日誌,可以快速的協助我們找到想要東西。

在該日誌系統中,我們使用兩個類:Debug和LogInFile,LogInFile主要是用來進行日誌寫入功能得。

1.顯示日誌
C# 輸出文字的語句:
Console.WriteLine(info, param);
在現實日誌上,我們只是對上面語句進行了一層封裝而已。
實現:

   /// <summary>        /// 資訊        /// </summary>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogInfo(string info, params object[] param)        {            LogInfo("", info.ToString(), param);        }        /// <summary>        /// 資訊        /// </summary>        /// <param name="info"></param>        public static void LogInfo(object info)        {            LogInfo("", info.ToString(), null);        }        /// <summary>        /// 自訂資訊        /// </summary>        /// <param name="genre"></param>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogInfo(string genre, string info, params object[] param)        {            SetColor(genre, ColorConfig.InfoColor, info,param);            LogInFileInfo lifi = WriteLine(genre, LogGenreEnum.Info, info, param);            if(lifi!=null)                SendEamil(genre, LogGenreEnum.Info, string.Format("{0} - Info:{1}", DateTime.Now, string.Format(info, param)), lifi.GetMessage);        }        /// <summary>        /// 錯誤        /// </summary>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogError(string info, params object[] param)        {            LogError("", info.ToString(), param);        }        /// <summary>        /// 錯誤        /// </summary>        /// <param name="info"></param>        public static void LogError(object info)        {            LogError("", info.ToString(), null);        }        /// <summary>        /// 錯誤        /// </summary>        /// <param name="genre"></param>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogError(string genre, string info, params object[] param)        {            SetColor(genre, ColorConfig.ErrorColor, info,param);            LogInFileInfo lifi = WriteLine(genre, LogGenreEnum.Error, info, param);            if(lifi!=null)                SendEamil(genre, LogGenreEnum.Warring, string.Format("{0} - Error:{1}", DateTime.Now, string.Format(info, param)), lifi.GetMessage);        }        /// <summary>        /// 警告        /// </summary>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogWarring(string info, params object[] param)        {            LogWarring("", info, param);        }        /// <summary>        /// 警告        /// </summary>        /// <param name="info"></param>        public static void LogWarring(object info)        {            LogWarring("", info.ToString(), null);        }        /// <summary>        /// 警告        /// </summary>        /// <param name="genre"></param>        /// <param name="info"></param>        /// <param name="param"></param>        public static void LogWarring(string genre, string info, params object[] param)        {            SetColor(genre, ColorConfig.WarringColor, info,param);            LogInFileInfo lifi = WriteLine(genre, LogGenreEnum.Warring, info, param);            //發送郵件            if (lifi != null)                SendEamil(genre, LogGenreEnum.Warring, string.Format("{0} - Warring:{1}", DateTime.Now, string.Format(info, param)), lifi.GetMessage);        }        /// <summary>        /// 異常資訊        /// </summary>        /// <param name="ex"></param>        /// <param name="tag"></param>        public static void LogException(Exception ex, string tag = "")        {            LogException("", ex, tag);        }        /// <summary>        /// 輸出異常        /// </summary>        /// <param name="ex"></param>        /// <param name="tag"></param>        public static void LogException(string genre, Exception ex, string tag = "")        {            string info = string.Empty;            info += string.Format("異常資訊 {0} - {1} " + Environment.NewLine, tag, ex.Message);            info += string.Format("\t異常對象:{0}" + Environment.NewLine, ex.Source);            info += "\t異常堆棧:" + Environment.NewLine + "\t" + ex.StackTrace.Trim() + Environment.NewLine;            info += string.Format("\t觸發方法:{0}" + Environment.NewLine + Environment.NewLine, ex.TargetSite);            SetColor(genre, ColorConfig.ExcepitonColor, info);            LogInFileInfo lifi = WriteLine(genre,LogGenreEnum.Exception, info);            if (lifi != null)                SendEamil(genre, LogGenreEnum.Exception, string.Format("{0} - Exception:{1}", DateTime.Now, ex.Message), lifi.GetMessage);        }

上面只是進行一層封裝沒什麼好說的。
從上面可以看出,我將程式裡的資訊分為四類:

        public enum LogGenreEnum : int        {            /// <summary>            /// 資訊            /// </summary>            Info = 2,            /// <summary>            /// 錯誤            /// </summary>            Error = 4,            /// <summary>            /// 警告            /// </summary>            Warring = 8,            /// <summary>            /// 異常            /// </summary>            Exception = 16        }

感覺這4類已經足夠用了。
2.寫入本地檔案
我的想法是:
1.建立一個佇列儲存體日誌資訊
2.開啟別的線程進行檔案寫入,線程數量可以進行設定,預設為3條
3.每個線程每次可以寫入N條日誌,日誌資料可以設定,預設100條
4.當CPU的使用率低於多少數值時,才進行寫入,使用率可以設定,預設30%(我的想法是,在電腦閒置時候進行寫入,但是我不知道怎麼才能判斷電腦是否在空閑狀態,所以用cpu的使用率。這裡有一個問題就是我在擷取CPU使用率的時候感覺很慢,不知道為什麼,大家有什麼辦法嗎。)
5.記錄檔每天一個,如果檔案大小大於50M則自動建立新的檔案(剛想起來,還沒寫,不過就是判斷檔案大小,然後建立一個就行了)
6.線程每隔多少秒進行一次寫入,時間也是可以進行配置的。

完整的LogInFile類

using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;using System.IO;namespace SvEngine.Log{    public class LogInFile    {        PerformanceCounter cpuRate = new PerformanceCounter("Processor", "% Processor Time", "_Total");        public List<LogInFileInfo> MessageStack = new List<LogInFileInfo>();        public void AddMessage(LogInFileInfo message)        {            lock (MessageStack) { MessageStack.Add(message); }        }        /// <summary>        /// 開始寫入檔案        /// </summary>        public void StartInFile()        {            while (true)            {                lock (MessageStack)                {                    if (MessageStack.Count < 1)                    {                        Thread.Sleep(Debug.InFileConfig.LogInFileWriteInterval);                        continue;                    }                    if (cpuRate.NextValue() > Debug.InFileConfig.CpuRate)                    {                        Thread.Sleep(Debug.InFileConfig.LogInFileWriteInterval);                        continue;                    }                    List<LogInFileInfo> writeList = new List<LogInFileInfo>();                    if (MessageStack.Count > Debug.InFileConfig.LogInFileWriteNum)                    {                        writeList.AddRange(MessageStack.GetRange(0, Debug.InFileConfig.LogInFileWriteNum));                        MessageStack.RemoveRange(0, Debug.InFileConfig.LogInFileWriteNum);                    }                    else                    {                        writeList.AddRange(MessageStack);                        MessageStack.Clear();                    }                    string infoMessage = string.Empty;                    string errorMessage = string.Empty;                    string waringMessage = string.Empty;                    //寫入檔案                    for (int i = 0; i < writeList.Count; i++)                    {                        LogInFileInfo curMes = writeList[i];                        switch (curMes.Genre)                        {                            case Debug.LogGenreEnum.Info:                                infoMessage += curMes.GetMessage;                                break;                            case Debug.LogGenreEnum.Error:                            case Debug.LogGenreEnum.Exception:                                errorMessage += curMes.GetMessage;                                break;                            case Debug.LogGenreEnum.Warring:                                waringMessage += curMes.GetMessage;                                break;                        }                        curMes.Dispose();                    }                    WriteText(Debug.LogGenreEnum.Info,infoMessage);                    WriteText(Debug.LogGenreEnum.Error, errorMessage);                    WriteText(Debug.LogGenreEnum.Warring, waringMessage);                    writeList = null;                }                //等待執行                Thread.Sleep(Debug.InFileConfig.LogInFileWriteInterval);            }        }        private void WriteText(Debug.LogGenreEnum genre,string text)        {            //檔案寫入            string filePath = string.Format(@"{0}\{1}\", Debug.InFileConfig.LogPath, genre.ToString());            string fileName = string.Format("{0}.txt", CurDate);            if (!Directory.Exists(filePath))                Directory.CreateDirectory(filePath);            if (!File.Exists(filePath + fileName))            {                FileStream fs = File.Create(filePath + fileName);                fs.Close();            }            using (FileStream fs = new FileStream(filePath + fileName, FileMode.Append, FileAccess.Write, FileShare.Write))            {                Byte[] info = new UTF8Encoding(true).GetBytes(text);                fs.Write(info, 0, info.Length);            }        }        private string CurDate        {            get { return string.Format("{0}-{1}-{2}", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); }        }    }    /// <summary>    /// 日誌資料    /// </summary>    public class LogInFileInfo:IDisposable    {        /// <summary>        /// Log類型        /// </summary>        public Debug.LogGenreEnum Genre;        /// <summary>        /// 建立時間        /// </summary>        public DateTime CreateTime;        /// <summary>        /// 內容        /// </summary>        public string MessageConnect;        /// <summary>        /// 擷取內容        /// </summary>        public string GetMessage        {            get { return string.Format("{0} - {1}"+ System.Environment.NewLine , CreateTime, MessageConnect); }        }        public void Dispose()        {        }    }}

PerformanceCounter cpuRate = new PerformanceCounter("Processor", "% Processor Time", "_Total");
這條語句就是擷取當前CPU的使用率,一定要注意,這個條語句最好不要放在方法中,第一次擷取的值為0,如果在方法中的每一次調用,總是會擷取的值為0的。

 if (cpuRate.NextValue() > Debug.CpuRate) {       Thread.Sleep(Debug.LogInFileWriteInterval);       continue;   }

這裡判斷了一下CPU的使用率。

  case Debug.LogGenreEnum.Error:  case Debug.LogGenreEnum.Exception:       errorMessage += curMes.GetMessage;

我將Error類型的日誌和異常類型的日誌,放在同一個檔案中。

if (!File.Exists(filePath + fileName)){     FileStream fs = File.Create(filePath + fileName);     fs.Close(); }

這裡檔案建立完畢後,一定要關閉一下,否則下面會報檔案被其他進程佔用的異常。

在InFileConfig類中,則存放了日誌寫入相關的配置和方法:

    /// <summary>    /// 日誌寫入配置    /// </summary>    public class InFileConfig    {        private LogInFile _logInFile;        private Thread[] _logInFileThread;        private bool _isInFile = false;        /// <summary>        /// 是否寫入檔案        /// </summary>        public bool IsInFile        {            get { return _isInFile; }            set            {                _isInFile = value;                if (_isInFile)                {                    _logInFile = new LogInFile();                    _logInFileThread = new Thread[_logInFileThreadNum];                    StartThread();                }                else                {                    CloseThread();                    _logInFile = null;                }            }        }        private int _inFileGenre = (int)LogGenreEnum.Info | (int)LogGenreEnum.Error | (int)LogGenreEnum.Exception | (int)LogGenreEnum.Warring;        /// <summary>        

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.