C# 简单的日志系统(服务端)

新的一年开始,也该开始学习一些新的东西,首先就是将去年写的C#服务器重新构思一下。
今天的目标:日志系统
需求:
1.显示日志
2.写入到本地文件
3.错误或异常日志需要通过邮件通知
4.可以自定日志类型(可有可无)

日志:
我个人理解,就是系统在运行过程中所产生的提示信息。比如,Debug程序的时候,除了进行断点调试,大多都是进行文本输出,来观察这一段程序书写是否正确。其次,就是我们经常碰到的错误或者捕获的异常信息等。通过观察日志,可以快速的帮助我们找到想要东西。

在该日志系统中,我们使用两个类:DebugLogInFileLogInFile主要是用来进行日志写入功能得。

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>
        /// 开启日志写入的类型
        /// </summary>
        public int InFileGenre
        {
            get { return _inFileGenre; }
            set { _inFileGenre = value; }
        }

        private string _logPath = "";
        /// <summary>
        /// 日志存储位置
        /// </summary>
        public string LogPath
        {
            get { return _logPath.Equals("") ? Environment.CurrentDirectory + @"\Log" : _logPath; }
            set { _logPath = value; }
        }

        private int _logInFileWriteInterval = 2000;
        /// <summary>
        /// 日志写入间隔时间
        /// </summary>
        public int LogInFileWriteInterval
        {
            get { return _logInFileWriteInterval; }
            set { _logInFileWriteInterval = value; }
        }

        private int _logInFileWriteNum = 99;
        /// <summary>
        /// 每次日志写入量
        /// </summary>
        public int LogInFileWriteNum
        {
            get { return _logInFileWriteNum; }
            set { _logInFileWriteNum = value; }
        }

        private int _logInFileThreadNum = 3;
        /// <summary>
        /// 日志写入线程数量
        /// </summary>
        public int LogInFileThreadNum
        {
            get { return _logInFileThreadNum; }
            set
            {
                _logInFileThreadNum = value;
                if (_logInFileThread != null)
                    CloseThread();
                _logInFileThread = new Thread[_logInFileThreadNum];
            }
        }

        private  float _cpuRate = 30;
        /// <summary>
        /// Cpu 使用率小于多少开始写入文件
        /// </summary>
        public float CpuRate
        {
            get { return _cpuRate; }
            set { _cpuRate = value; }
        }

        /// <summary>
        /// 添加消息
        /// </summary>
        /// <param name="message"></param>
        public void AddMessage(LogInFileInfo message)
        {
            _logInFile.AddMessage(message);
        }

        /// <summary>
        /// 开启线程
        /// </summary>
        private void StartThread()
        {
            for (int i = 0; i < _logInFileThread.Length; i++)
            {
                _logInFileThread[i] = new Thread(new ThreadStart(_logInFile.StartInFile));
                _logInFileThread[i].IsBackground = true;
                _logInFileThread[i].Start();
            }
        }

        /// <summary>
        /// 关闭线程
        /// </summary>
        private void CloseThread()
        {
            for (int i = 0; i < _logInFileThread.Length; i++)
            {
                if (_logInFileThread[i].IsAlive)
                    _logInFileThread[i].Abort();
            }
            _logInFileThread = null;
        }

    }

以上这些属性对写入日志进行相关配置。
StartThread()CloseThread()定义了线程开启和关闭。

InFileGenre 属性则定义了那些日志可以及进行文件写入
private int _inFileGenre = (int)LogGenreEnum.Info | (int)LogGenreEnum.Error | (int)LogGenreEnum.Exception | (int)LogGenreEnum.Warring;
默认下4中类型都可以进行写入。
日志写入大概就是这些内容。

3.邮件通知
邮件部分我也是参考其他作者的博客写的,下面放出地址:
参考地址 https://www.cnblogs.com/xiezunxu/articles/7421322.html

  /// <summary>
        /// 发送邮件,参考地址 https://www.cnblogs.com/xiezunxu/articles/7421322.html
        /// </summary>
        public static void SendEmail(string title,string body)
        {
            if (!EmailConfig.IsEmail  //不发送邮件
                || EmailConfig.SenderEmail.Equals(string.Empty)  //发送人为空
                || EmailConfig.ReceiverEamil.Count < 1  //接收人为空
                || EmailConfig.AuthorizationCode.Equals(string.Empty)  //授权码为空
                || EmailConfig.SmtpHost.Equals(string.Empty)) return; //主机名为空

            MailMessage mailMessage = new MailMessage();
            mailMessage.From = new MailAddress(EmailConfig.SenderEmail);
            for(int i = 0;i<EmailConfig.ReceiverEamil.Count;i++)
                mailMessage.To.Add(new MailAddress(EmailConfig.ReceiverEamil[i]));
            mailMessage.Subject = title;
            mailMessage.Body = body;

            SmtpClient client = new SmtpClient();
            client.Host =EmailConfig.SmtpHost;
            client.EnableSsl = true;
            client.UseDefaultCredentials = false;
            client.Credentials = new NetworkCredential(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode);
            client.Send(mailMessage);
        }
    }

上面这个方法就是邮件发送的主要方法。

4.自定义级别:
使用比较简单的方式:

  private static Dictionary<string, CustomGenre> _customGenre = new Dictionary<string, CustomGenre>();
  /// <summary>
    /// 自定义类型
    /// </summary>
    /// <param name="genre"></param>
    public static void CustomGenre(Dictionary<string, CustomGenre> genre)
    {
        _customGenre = genre;
    }

把自定义类型传进来,在调用其他输出方法是,设置参数string genre 即可,会先去匹配_customGenre 中是否有该类型。

    /// <summary>
    /// 颜色配置
    /// </summary>
    public class ColorConfig
    {

        /// <summary>
        /// 字体颜色
        /// </summary>
        public ConsoleColor FontColor
        {
            get { return Console.ForegroundColor; }
            set
            {
                Console.ForegroundColor = value;
            }
        }

        /// <summary>
        /// 默认颜色
        /// </summary>
        public ConsoleColor DefaultColor = ConsoleColor.White;
        /// <summary>
        /// 信息颜色
        /// </summary>
        public ConsoleColor InfoColor = ConsoleColor.White;
        /// <summary>
        /// 错误颜色
        /// </summary>
        public ConsoleColor ErrorColor = ConsoleColor.Red;
        /// <summary>
        /// 警告颜色
        /// </summary>
        public ConsoleColor WarringColor = ConsoleColor.Yellow;
        /// <summary>
        /// 异常颜色
        /// </summary>
        public ConsoleColor ExcepitonColor = ConsoleColor.Cyan;
    }

ColorConfig这个类型进行了一些颜色属性的配置。

测试:

 class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Environment.CurrentDirectory + @"\Log");
            Debug.InFileConfig.IsInFile = true;
            Debug.IsDebug = true;

            Debug.EmailConfig.SenderEmail = "***@qq.com";
            Debug.EmailConfig.ReceiverEamil.Add("***@qq.com");
            Debug.EmailConfig.SmtpHost = "smtp.qq.com";
            //此处在你邮箱中获取
            Debug.EmailConfig.AuthorizationCode = "******";

            Debug.EmailConfig.IsEmail = true;

            try
            {
                throw new Exception("这是一个测试异常");
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }

            for (int i = 0; i < 10; i++)
            {
                Thread t = new Thread(new ParameterizedThreadStart(Input));
                t.Start(i);
            }

            Console.ReadKey();
        }

        static void Input(object data)
        {
            int idnex = (int)data;
            for (int i = 0; i < 100; i++)
            {
                Debug.LogError("{0} - {1} 日志测试", idnex, i);
            }
        }

    }

这里写图片描述

成功收到邮件:
这里写图片描述

日志写入成功:
这里写图片描述

注意CPU的使用率大于设置的使用率是不会进行写入的,等到条件达成后才会进行写入。
完整的Debug类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;
using static SvEngine.Log.Debug;

namespace SvEngine.Log
{
    public class Debug
    {
        public enum LogGenreEnum : int
        {
            /// <summary>
            /// 信息
            /// </summary>
            Info = 2,
            /// <summary>
            /// 错误
            /// </summary>
            Error = 4,
            /// <summary>
            /// 警告
            /// </summary>
            Warring = 8,
            /// <summary>
            /// 异常
            /// </summary>
            Exception = 16
        }



        private static EmailConfig _emailConfig = new EmailConfig();
        /// <summary>
        /// 邮件配置
        /// </summary>
        public static EmailConfig EmailConfig
        {
            get {
                return _emailConfig;
            }
        }

        private static InFileConfig _inFileConfig = new InFileConfig();
        /// <summary>
        /// 写入日志配置
        /// </summary>
        public static InFileConfig InFileConfig {
            get {
                return _inFileConfig;
            }
        }

        private static ColorConfig _colorConfig = new ColorConfig();
        /// <summary>
        /// 颜色配置
        /// </summary>
        public static ColorConfig ColorConfig
        {
            get { return _colorConfig; }
        }

        private static bool _isDebug = true;
        /// <summary>
        /// 是否显示
        /// </summary>
        public static bool IsDebug
        {
            get { return _isDebug; }
            set { _isDebug = value; }
        }

        private static bool _isEnable = true;
        /// <summary>
        /// 是否开启
        /// </summary>
        public static bool IsEnable
        {
            get
            {
                return _isEnable;
            }
            set { _isEnable = value; }
        }

        private static Dictionary<string, CustomGenre> _customGenre = new Dictionary<string, CustomGenre>();
        /// <summary>
        /// 自定义类型
        /// </summary>
        /// <param name="genre"></param>
        public static void CustomGenre(Dictionary<string, CustomGenre> genre)
        {
            _customGenre = genre;
        }

        /// <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);
        }

        /// <summary>
        /// 设置颜色
        /// </summary>
        /// <param name="genre"></param>
        /// <param name="defaultColor"></param>
        /// <param name="info"></param>
        /// <param name="param"></param>
        private static void SetColor(string genre,ConsoleColor defaultColor, string info, params object[] param)
        {
            if (_customGenre.ContainsKey(genre))

                Console.ForegroundColor = _customGenre[genre].ConsoleColor;
            else
                Console.ForegroundColor = defaultColor;

            DebugWrite(info,param);

        }

        /// <summary>
        /// 显示日志
        /// </summary>
        /// <param name="info"></param>
        /// <param name="param"></param>
        private static void DebugWrite(string info, params object[] param)
        {
            if (IsEnable && IsDebug)
                Console.WriteLine(info, param);
            Console.ForegroundColor = ColorConfig.DefaultColor;
        }

        /// <summary>
        /// 日志写入
        /// </summary>
        /// <param name="Genre"></param>
        /// <param name="genre"></param>
        /// <param name="info"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private static LogInFileInfo WriteLine(string Genre, LogGenreEnum genre, string info, params object[] param)
        {
            if (IsEnable&& InFileConfig.IsInFile)
            {
                if (_customGenre.ContainsKey(Genre) && !_customGenre[Genre].IsInFile)
                    return null;

                if (Genre.Equals("")&&(InFileConfig.InFileGenre & (int)genre) <= 0)
                    return null;

                LogInFileInfo fileInfo = new LogInFileInfo();
                fileInfo.CreateTime = DateTime.Now;
                fileInfo.MessageConnect = string.Format(info, param);
                if (!_customGenre.ContainsKey(Genre))
                {

                    //写入文件操作
                    fileInfo.Genre = genre;
                    //添加消息
                    InFileConfig.AddMessage(fileInfo);
                    return fileInfo;
                }
                CustomGenre cg = _customGenre[Genre];
                fileInfo.Genre = cg.GenreEnum;
                InFileConfig.AddMessage(fileInfo);
                return fileInfo;
            }
            return null;
        }

        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="Genre"></param>
        /// <param name="genre"></param>
        /// <param name="tile"></param>
        /// <param name="body"></param>
        private static void SendEamil(string Genre, LogGenreEnum genre, string tile,string body)
        {
            //自定义小于1 使用默认
            if (_customGenre.Count > 0)
            {
                if (_customGenre.ContainsKey(Genre) && _customGenre[Genre].IsEmail)
                    SendEmail(tile,body);
            }
            else //使用自定义
            {
                if ((EmailConfig.EmailGenre & (int)genre) > 0)
                {
                    SendEmail(tile,body);
                }
            }
        }

        /// <summary>
        /// 发送邮件,参考地址 https://www.cnblogs.com/xiezunxu/articles/7421322.html
        /// </summary>
        public static void SendEmail(string title,string body)
        {
            if (!EmailConfig.IsEmail  //不发送邮件
                || EmailConfig.SenderEmail.Equals(string.Empty)  //发送人为空
                || EmailConfig.ReceiverEamil.Count < 1  //接收人为空
                || EmailConfig.AuthorizationCode.Equals(string.Empty)  //授权码为空
                || EmailConfig.SmtpHost.Equals(string.Empty)) return; //主机名为空

            MailMessage mailMessage = new MailMessage();
            mailMessage.From = new MailAddress(EmailConfig.SenderEmail);
            for(int i = 0;i<EmailConfig.ReceiverEamil.Count;i++)
                mailMessage.To.Add(new MailAddress(EmailConfig.ReceiverEamil[i]));
            mailMessage.Subject = title;
            mailMessage.Body = body;

            SmtpClient client = new SmtpClient();
            client.Host =EmailConfig.SmtpHost;
            client.EnableSsl = true;
            client.UseDefaultCredentials = false;
            client.Credentials = new NetworkCredential(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode);
            client.Send(mailMessage);
        }
    }

    /// <summary>
    /// 自定义级别
    /// </summary>
    public class CustomGenre
    {
        public string GenreName;
        public ConsoleColor ConsoleColor;
        public bool IsEmail = false;
        public bool IsInFile = false;
        public LogGenreEnum GenreEnum = LogGenreEnum.Info;
    }

    /// <summary>
    /// 邮箱配置
    /// </summary>
    public class EmailConfig
    {
        private  bool _isEmail = false;
        /// <summary>
        /// 是否发送邮件提示
        /// </summary>
        public bool IsEmail
        {
            get { return _isEmail; }
            set { _isEmail = value; }
        }

        private  int _emailGenre = (int)LogGenreEnum.Error | (int)LogGenreEnum.Exception;
        /// <summary>
        /// 发送邮件类型
        /// </summary>
        public int EmailGenre
        {
            get { return _emailGenre; }
            set
            {
                _emailGenre = value;
            }
        }

        /// <summary>
        /// 发送者
        /// </summary>
        public string SenderEmail = string.Empty;
        /// <summary>
        /// 接收方
        /// </summary>
        public List<string> ReceiverEamil = new List<string>();
        /// <summary>
        /// qq 为  "smtp.qq.com" 126 为 "smtp.126.com"
        /// </summary>
        public string SmtpHost = string.Empty;
        /// <summary>
        /// 授权码,需要在邮箱中获取
        /// </summary>
        public string AuthorizationCode = string.Empty;
    }

    /// <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>
        /// 开启日志写入的类型
        /// </summary>
        public int InFileGenre
        {
            get { return _inFileGenre; }
            set { _inFileGenre = value; }
        }

        private string _logPath = "";
        /// <summary>
        /// 日志存储位置
        /// </summary>
        public string LogPath
        {
            get { return _logPath.Equals("") ? Environment.CurrentDirectory + @"\Log" : _logPath; }
            set { _logPath = value; }
        }

        private int _logInFileWriteInterval = 2000;
        /// <summary>
        /// 日志写入间隔时间
        /// </summary>
        public int LogInFileWriteInterval
        {
            get { return _logInFileWriteInterval; }
            set { _logInFileWriteInterval = value; }
        }

        private int _logInFileWriteNum = 99;
        /// <summary>
        /// 每次日志写入量
        /// </summary>
        public int LogInFileWriteNum
        {
            get { return _logInFileWriteNum; }
            set { _logInFileWriteNum = value; }
        }

        private int _logInFileThreadNum = 3;
        /// <summary>
        /// 日志写入线程数量
        /// </summary>
        public int LogInFileThreadNum
        {
            get { return _logInFileThreadNum; }
            set
            {
                _logInFileThreadNum = value;
                if (_logInFileThread != null)
                    CloseThread();
                _logInFileThread = new Thread[_logInFileThreadNum];
            }
        }

        private  float _cpuRate = 30;
        /// <summary>
        /// Cpu 使用率小于多少开始写入文件
        /// </summary>
        public float CpuRate
        {
            get { return _cpuRate; }
            set { _cpuRate = value; }
        }

        /// <summary>
        /// 添加消息
        /// </summary>
        /// <param name="message"></param>
        public void AddMessage(LogInFileInfo message)
        {
            _logInFile.AddMessage(message);
        }

        /// <summary>
        /// 开启线程
        /// </summary>
        private void StartThread()
        {
            for (int i = 0; i < _logInFileThread.Length; i++)
            {
                _logInFileThread[i] = new Thread(new ThreadStart(_logInFile.StartInFile));
                _logInFileThread[i].IsBackground = true;
                _logInFileThread[i].Start();
            }
        }

        /// <summary>
        /// 关闭线程
        /// </summary>
        private void CloseThread()
        {
            for (int i = 0; i < _logInFileThread.Length; i++)
            {
                if (_logInFileThread[i].IsAlive)
                    _logInFileThread[i].Abort();
            }
            _logInFileThread = null;
        }

    }

    /// <summary>
    /// 颜色配置
    /// </summary>
    public class ColorConfig
    {

        /// <summary>
        /// 字体颜色
        /// </summary>
        public ConsoleColor FontColor
        {
            get { return Console.ForegroundColor; }
            set
            {
                Console.ForegroundColor = value;
            }
        }

        /// <summary>
        /// 默认颜色
        /// </summary>
        public ConsoleColor DefaultColor = ConsoleColor.White;
        /// <summary>
        /// 信息颜色
        /// </summary>
        public ConsoleColor InfoColor = ConsoleColor.White;
        /// <summary>
        /// 错误颜色
        /// </summary>
        public ConsoleColor ErrorColor = ConsoleColor.Red;
        /// <summary>
        /// 警告颜色
        /// </summary>
        public ConsoleColor WarringColor = ConsoleColor.Yellow;
        /// <summary>
        /// 异常颜色
        /// </summary>
        public ConsoleColor ExcepitonColor = ConsoleColor.Cyan;
    }

}
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建宁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值