C# 简单的日志系统(服务端)
2018-02-27 15:58
721 查看
新的一年开始,也该开始学习一些新的东西,首先就是将去年写的C#服务器重新构思一下。
今天的目标:日志系统
需求:
1.显示日志
2.写入到本地文件
3.错误或异常日志需要通过邮件通知
4.可以自定日志类型(可有可无)
日志:
我个人理解,就是系统在运行过程中所产生的提示信息。比如,Debug程序的时候,除了进行断点调试,大多都是进行文本输出,来观察这一段程序书写是否正确。其次,就是我们经常碰到的错误或者捕获的异常信息等。通过观察日志,可以快速的帮助我们找到想要东西。
在该日志系统中,我们使用两个类:
1.显示日志
C# 输出文字的语句:
在现实日志上,我们只是对上面语句进行了一层封装而已。
实现:
上面只是进行一层封装没什么好说的。
从上面可以看出,我将程序里的信息分为四类:
感觉这4类已经足够用了。
2.写入本地文件
我的想法是:
1.创建一个队列存储日志信息
2.开启别的线程进行文件写入,线程数量可以进行设置,默认为3条
3.每个线程每次可以写入N条日志,日志数据可以设置,默认100条
4.当CPU的使用率低于多少数值时,才进行写入,使用率可以设置,默认30%(我的想法是,在电脑空闲的时候进行写入,但是我不知道怎么才能判断电脑是否在空闲状态,所以用cpu的使用率。这里有一个问题就是我在获取CPU使用率的时候感觉很慢,不知道为什么,大家有什么办法吗?)
5.日志文件每天一个,如果文件大小大于50M则自动创建新的文件(刚想起来,还没写,不过就是判断文件大小,然后新建一个就行了)
6.线程每隔多少秒进行一次写入,时间也是可以进行配置的。
完整的LogInFile类
这条语句就是获取当前CPU的使用率,一定要注意,这个条语句最好不要放在方法中,第一次获取的值为0,如果在方法中的每一次调用,总是会获取的值为0的。
这里判断了一下CPU的使用率。
我将Error类型的日志和异常类型的日志,放在同一个文件中。
这里文件创建完毕后,一定要关闭一下,否则下面会报文件被其他进程占用的异常。
在InFileConfig类中,则存放了日志写入相关的配置和方法:
以上这些属性对写入日志进行相关配置。
默认下4中类型都可以进行写入。
日志写入大概就是这些内容。
3.邮件通知
邮件部分我也是参考其他作者的博客写的,下面放出地址:
参考地址 https://www.cnblogs.com/xiezunxu/articles/7421322.html
上面这个方法就是邮件发送的主要方法。
4.自定义级别:
使用比较简单的方式:
把自定义类型传进来,在调用其他输出方法是,设置参数
测试:
![](https://img-blog.csdn.net/20180227155402579?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTgxOTIxNjE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
成功收到邮件:
![](https://img-blog.csdn.net/20180227155416232?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTgxOTIxNjE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
日志写入成功:
![](https://img-blog.csdn.net/20180227155432791?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTgxOTIxNjE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
注意CPU的使用率大于设置的使用率是不会进行写入的,等到条件达成后才会进行写入。
完整的Debug类:
今天的目标:日志系统
需求:
1.显示日志
2.写入到本地文件
3.错误或异常日志需要通过邮件通知
4.可以自定日志类型(可有可无)
日志:
我个人理解,就是系统在运行过程中所产生的提示信息。比如,Debug程序的时候,除了进行断点调试,大多都是进行文本输出,来观察这一段程序书写是否正确。其次,就是我们经常碰到的错误或者捕获的异常信息等。通过观察日志,可以快速的帮助我们找到想要东西。
在该日志系统中,我们使用两个类:
Debug和
LogInFile,
LogInFile主要是用来进行日志写入功能得。
1.显示日志
C# 输出文字的语句:
Console.WriteLine(info, param);
在现实日志上,我们只是对上面语句进行了一层封装而已。
实现:
/// <summary> /// 信息 /// </summary> /// <param name="info"></param> /// <param name="param"></param>< 4000 /span> 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> /// 异常 /// </su 1e943 mmary> 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; } }
相关文章推荐
- 基于C#中的Trace实现一个简单的日志系统
- 用C#构建一个简单的采集系统之二—采集任务实时显示
- 程序员简单打造一个灵活智能的自动化运维系统C#实例程序
- FFmpeg源代码简单分析:日志输出系统(av_log()等)
- C# 调用系统API 内核 简单样例
- 日志收集系统Flume的简单安装Centos7
- Log4j日志管理系统简单使用说明
- 可替代log4j日志的c#简单日志类队列实现类代码分享
- 一个简单又高效的日志系统
- C#:项目一 简单的信息管理系统
- Log4j日志管理系统简单使用说明
- 0306数据备份整理-【系统日志】C#代码
- C#监视文件系统如此简单
- c#简单的客车售票系统(《c#程序设计慕课版-甘勇 尚展垒编著》第二章上机指导)
- 使用Node.js + MongoDB实现一个简单的日志分析系统
- C#_会员管理系统:开发四(日志查看)
- Log4j日志管理系统简单使用说明
- 使用socket实现简单的客户端和服务端通信(C#语言)
- 刚整了个在线查看系统项目日志的方法,步骤挺简单的,分享下。
- 一个用hibernate+struts写的简单日志系统