对于.net环境而言,日志的开源组件有很多,像Nlog,log4net等等,而我今天要介绍的是我的日志组件VLog,呵呵,事实上实现原理与作用都大同小异。
作用:记录程序运行中的相关信息
特点:提供了消息日志,错误日志,调试日志,警告日志,崩溃日志等等
优势:提供了多种日志实现的方式,如SQL数据库,XML文本,WIN日志等等
配置:它可以通过配置文件进行设置,提供了日志级别和记录方式等参数
说明:VLog项目层次分明,一个接口,一个基类,5个实现的功能类,一切都是那么自然,下面看一下结构图:
一个接口:
1 namespace VLog 2 { 3 /// <summary> 4 /// 日志操作规范 5 /// </summary> 6 public interface IVLog 7 { 8 /// <summary> 9 /// 调试型日志 10 /// </summary> 11 /// <param name="msg"></param> 12 void DebugLog(string msg); 13 /// <summary> 14 /// 信息型日志 15 /// </summary> 16 /// <param name="msg"></param> 17 void InfoLog(string msg); 18 /// <summary> 19 /// 警告型日志 20 /// </summary> 21 /// <param name="msg"></param> 22 void WarnLog(string msg); 23 /// <summary> 24 /// 错误型日志 25 /// </summary> 26 /// <param name="msg"></param> 27 void ErrorLog(string msg); 28 /// <summary> 29 /// 系统崩溃型日志 30 /// </summary> 31 /// <param name="msg"></param> 32 void FatalLog(string msg); 33 } 34 }
一个基类:
1 namespace VLog 2 { 3 /// <summary> 4 /// VLog 基类 5 /// </summary> 6 public abstract class VLogBase : IVLog 7 { 8 #region Protected Properties 9 /// <summary> 10 /// 获取执行路径 11 /// </summary> 12 /// <returns>返回 执行路径</returns> 13 protected string GetSenders() 14 { 15 StringBuilder sb = new StringBuilder(); 16 StackFrame[] frames = new StackTrace(true).GetFrames(); 17 for (int index = 2; index < frames.Length; index++) 18 { 19 if (frames[index].GetMethod().ReflectedType == null) 20 { 21 sb.AppendFormat("[systemfuntion:{0}]->", frames[index].GetMethod().Name); 22 } 23 else 24 { 25 sb.AppendFormat("[{0}]->", frames[index].GetMethod().ReflectedType.Name); 26 } 27 } 28 //return sb.ToString(0, sb.Length - 2); 29 return string.Empty; 30 } 31 32 /// <summary> 33 /// 得到当现异常的URL 34 /// 子类可以根据自己的逻辑去复写本属性 35 /// </summary> 36 protected virtual string RequestReffer { get { return HttpContext.Current.Request.Url.AbsoluteUri; } } 37 38 /// <summary> 39 /// 得到当前异常URL的请求方式(POST,GET或HEAD) 40 /// 子类可以根据自己的逻辑去复写本属性 41 /// </summary> 42 protected virtual string HttpMethod { get { return HttpContext.Current.Request.HttpMethod; } } 43 44 /// <summary> 45 /// 写日志地址 或是 DBConnectionStr 46 /// </summary> 47 protected string Path { get; set; } 48 #endregion 49 50 #region Protected Methods 51 /// <summary> 52 /// 写日志,子类必须去实现这个方法 53 /// </summary> 54 /// <param name="text">内容</param> 55 /// <returns>返回是否成功</returns> 56 protected abstract bool Write(VLogEntity entity); 57 #endregion 58 59 #region Delegates & Events 60 /// <summary> 61 /// 日志相关委托 62 /// </summary> 63 public delegate void VLogEventHandler(object sender, VLogsEventArgs e); 64 65 /// <summary> 66 /// 添加日志事件 67 /// </summary> 68 public static event VLogEventHandler AddVLog; 69 70 /// <summary> 71 /// 触发写日志事件 72 /// </summary> 73 /// <param name="entity"></param> 74 public void OnAddVLog(VLogEntity entity) 75 { 76 try 77 { 78 if (AddVLog != null) 79 { 80 AddVLog(this, new VLogsEventArgs(entity)); 81 } 82 } 83 catch (Exception) 84 { 85 throw; 86 } 87 } 88 #endregion 89 90 #region Private Fields 91 static int configLevel = Convert.ToInt32(ConfigurationManager.AppSettings["VLogLevel"]); 92 93 #endregion 94 95 #region IVLog 成员 96 97 public virtual void DebugLog(string msg) 98 { 99 if (configLevel >= (int)VLog.VLogLevel.Debug) 100 this.Write(new VLogEntity { ExceptionID = Guid.NewGuid().ToString(), FullInfo = msg, Level = VLogLevel.Debug }); 101 } 102 103 public virtual void InfoLog(string msg) 104 { 105 if (configLevel >= (int)VLog.VLogLevel.Info) 106 this.Write(new VLogEntity { ExceptionID = Guid.NewGuid().ToString(), FullInfo = msg, Level = VLogLevel.Info }); 107 } 108 109 public virtual void WarnLog(string msg) 110 { 111 if (configLevel >= (int)VLog.VLogLevel.Warn) 112 this.Write(new VLogEntity { ExceptionID = Guid.NewGuid().ToString(), FullInfo = msg, Level = VLogLevel.Warn }); 113 } 114 115 public virtual void ErrorLog(string msg) 116 { 117 if (configLevel >= (int)VLog.VLogLevel.Error) 118 this.Write(new VLogEntity { ExceptionID = Guid.NewGuid().ToString(), FullInfo = msg, Level = VLogLevel.Error }); 119 } 120 121 public void FatalLog(string msg) 122 { 123 if (configLevel >= (int)VLog.VLogLevel.Fatal) 124 this.Write(new VLogEntity { ExceptionID = Guid.NewGuid().ToString(), FullInfo = msg, Level = VLogLevel.Fatal }); 125 } 126 127 #endregion 128 129 } 130 }
一个生产日志的工厂:
1 namespace VLog 2 { 3 /// <summary> 4 /// 日志生产工厂 5 /// </summary> 6 public class VLogFactory 7 { 8 /// <summary> 9 /// 创建日志对象 10 /// </summary> 11 /// <returns></returns> 12 public static VLogBase CreateVLog() 13 { 14 if (ConfigurationManager.AppSettings["VLog"] == null) 15 return new VLog.NullVLog(); 16 return (VLogBase)System.Reflection.Assembly.Load("VLog").CreateInstance("VLog." 17 + ConfigurationManager.AppSettings["VLog"]); 18 } 19 } 20 }
五种实现日志的对象
1 /// <summary> 2 /// 空日志 3 /// </summary> 4 public class NullVLog : VLogBase 5 { 6 protected override bool Write(VLogEntity entity) 7 { 8 return true; 9 } 10 }
1 /// <summary> 2 /// SQL数据库 日志 3 /// </summary> 4 public class SqlVLog : VLogBase 5 { 6 public SqlVLog() 7 { 8 this.Path = LogCommons.GetPath(PathType.DataBase); 9 } 10 11 /// <summary> 12 /// 写日志 13 /// </summary> 14 /// <param name="text"></param> 15 /// <returns></returns> 16 protected override bool Write(VLogEntity entity) 17 { 18 19 using (SqlConnection sqlconn = new SqlConnection(this.Path)) 20 { 21 using (SqlCommand sqlcomm = new SqlCommand( 22 "INSERT INTO [Web_ExceptionLog]([ExceptionID],[FullInfo],[Senders],[OccurTime],[HttpMethod],[Level]) VALUES (@ExceptionID,@FullInfo,@Senders,@OccurTime,@HttpMethod,@Level);" 23 , sqlconn)) 24 { 25 SqlParameter parameter = new SqlParameter("@ExceptionID", SqlDbType.VarChar, 36); 26 parameter.Value = entity.ExceptionID; 27 sqlcomm.Parameters.Add(parameter); 28 29 parameter = new SqlParameter("@FullInfo", SqlDbType.NText); 30 parameter.Value = string.Format(@"<p>{0}</p>" 31 , entity.FullInfo 32 ); 33 sqlcomm.Parameters.Add(parameter); 34 35 parameter = new SqlParameter("@OccurTime", SqlDbType.DateTime, 4); 36 parameter.Value = DateTime.Now; 37 sqlcomm.Parameters.Add(parameter); 38 39 parameter = new SqlParameter("@Senders", SqlDbType.VarChar, 2000); 40 parameter.Value = base.RequestReffer; 41 sqlcomm.Parameters.Add(parameter); 42 43 parameter = new SqlParameter("@HttpMethod", SqlDbType.VarChar, 50); 44 parameter.Value = base.HttpMethod; 45 sqlcomm.Parameters.Add(parameter); 46 47 parameter = new SqlParameter("@Level", SqlDbType.Int); 48 parameter.Value = entity.Level; 49 sqlcomm.Parameters.Add(parameter); 50 51 sqlconn.Open(); 52 sqlcomm.ExecuteNonQuery(); 53 sqlconn.Close(); 54 } 55 } 56 OnAddVLog(entity); //触发写日志事件,外部订阅这个事件的对象将被执行 57 return true; 58 } 59 60 61 }
1 namespace VLog 2 { 3 /// <summary> 4 /// txt 日志 5 /// </summary> 6 public class TxtVLog : VLogBase 7 { 8 public TxtVLog() 9 { 10 this.Path = LogCommons.GetPath(PathType.Txt); 11 } 12 13 protected override bool Write(VLogEntity entity) 14 { 15 string text = string.Format(@" 16 Senders: {0} 17 Content: {1} 18 Date: {2} 19 Level: {3} 20 ", base.GetSenders() 21 , entity.FullInfo 22 , DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff") 23 , entity.Level 24 ); 25 26 File.AppendAllText(this.Path, text, Encoding.UTF8); 27 28 return true; 29 } 30 } 31 }
1 namespace VLog 2 { 3 /// <summary> 4 /// windows 日志 5 /// </summary> 6 public class WindowsEventVLog : VLogBase 7 { 8 public WindowsEventVLog() 9 { 10 this.Path = LogCommons.GetPath(PathType.WindowsEvent); 11 } 12 13 protected override bool Write(VLogEntity entity) 14 { 15 string text = string.Format(@" 16 Senders: {0} 17 Content: {1} 18 Date: {2} 19 Level: {3} 20 ", base.GetSenders() 21 , entity.FullInfo 22 , DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff") 23 , entity.Level 24 ); 25 System.Diagnostics.EventLog.WriteEntry(this.Path, text, System.Diagnostics.EventLogEntryType.Error); 26 return true; 27 } 28 } 29 }
1 namespace VLog 2 { 3 /// <summary> 4 /// XML 日志 5 /// </summary> 6 public class XmlVLog : VLogBase 7 { 8 9 public XmlDocument xmlDocument = null; 10 11 public XmlVLog() 12 { 13 this.Path = LogCommons.GetPath(PathType.Xml); 14 if (!File.Exists(this.Path)) 15 { 16 ReCreate(this.Path); 17 } 18 this.xmlDocument = new XmlDocument(); 19 this.xmlDocument.Load(this.Path); 20 } 21 22 static void ReCreate(string path) 23 { 24 XmlDocument xmlDocument = new XmlDocument(); 25 XmlDeclaration xmldecl = xmlDocument.CreateXmlDeclaration("1.0", "utf-8", null); 26 xmlDocument.AppendChild(xmldecl); 27 XmlElement ele = xmlDocument.CreateElement("root"); 28 xmlDocument.AppendChild(ele); 29 xmlDocument.Save(path); 30 } 31 32 protected override bool Write(VLogEntity entity) 33 { 34 XmlElement ele = this.xmlDocument.CreateElement("item"); 35 ele.InnerXml = string.Format( 36 @"<Senders>{0}</Senders> 37 <Content>{1}</Content> 38 <Date>{2}</Date> 39 <Level>{3}</Level> 40 " , base.GetSenders() 41 , entity.FullInfo 42 , DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff") 43 , entity.Level 44 ); 45 this.xmlDocument.DocumentElement.AppendChild(ele); 46 xmlDocument.Save(this.Path); 47 return true; 48 } 49 } 50 }
最后在配置文件里再进行设置就OK了,呵呵!
本文转自博客园张占岭(仓储大叔)的博客,原文链接:我心中的核心组件(可插拔的AOP)~第一回 日志记录组件之自主的Vlog,如需转载请自行联系原博主。