日志记录器
项目名称 : Logger
项目介绍
适用范围:异常日志,操作日志,交互日志等等 各种日志
日志存储方式:SqlServer , MySql, Oracle, Text(即文本文件)
日志写入类型 :Immediate(即时) Queue(队列)
日志配置文件:LogConfig.xml
1.配置文件介绍
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configurations> 3 <setting model="immediate" writer="sqlserver" connectionstring="server=.;database=Log;uid=sa;password=sqlpass;"></setting> 4 <sections> 5 <section type="LogService.Domain.ExceptionLog" catalog="ExceptionLog"> 6 <setting model="queue" writer="sqlserver" maxcount="1" interval="2" connectionstring="server=.;database=Log;uid=sa;password=sqlpass;"></setting> 7 <mapping property="Message"></mapping> 8 <mapping property="Source"></mapping> 9 <mapping property="TargetSite"></mapping> 10 <mapping property="StackTrace"></mapping> 11 <mapping property="ErrorTime"></mapping> 12 <mapping property="Remark"></mapping> 13 </section> 14 </sections> 15 </configurations>
文件介绍:
sections节点:主要起到分类的作用,比如一个异常日志就需要一个sections
section节点:日志分类属性节点
type:日志实体类型的命名空间
catalog:写入数据的表名
setting节点: 主要设置写入类型,写入方式以及写入数据链接(这个节点在sections下面如果则节点不存在则采购最跟节点下面做为默认值)
model(写入类型):queue(队列的方式写入)
如果model为queue类型 则需要设置2个额外的属性
maxcount :当内存存储日志条数到达maxcount条时则写入数据库或者文件
interval:如果内存存储日志条数没有到达maxcount时间 但是时间间隔为interval秒时也会写入数据库或文件
writer(写入方式):SqlServer , MySql, Oracle
connectionstring(数据库链接):如果是写入数据则需要配置这个数据
mapping : 日志实体对应字段描述
property:字段名称
2.服务层介绍(LogService)
服务层即指日志组件提供给外界写入日志的方法
该类只公布1个方法,WriteLog 写入类型
该方法提供3个重置
WriteLog(object item) 此方法会根据Objcet类型的命名空间去读取配置 并且解析出日志实体对象
WriteLog(string content) 写入文本日志
WriteLog(string content, string path) 写入文本日志并指定日志路径
1 /// <summary> 2 /// 日志记录器 3 /// </summary> 4 public class LogService 5 { 6 /// <summary> 7 /// 添加日志 8 /// </summary> 9 /// <param name="item">日志内容</param> 10 /// <returns>返回记录结果 成功?true:false</returns> 11 public static bool WriteLog(object item) 12 { 13 return item != null && Allocator.Intance.Execute(item); 14 } 15 16 /// <summary> 17 /// 记录文本日志 18 /// </summary> 19 /// <param name="content">日志内容</param> 20 /// <returns>返回记录结果 成功?true:false</returns> 21 public static bool WriteLog(string content) 22 { 23 return WriteLog(content, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs")); 24 } 25 /// <summary> 26 /// 记录文本日志 27 /// </summary> 28 /// <param name="content">日志内容</param> 29 /// <param name="path">日志路径</param> 30 /// <returns>返回记录结果 成功?true:false</returns> 31 public static bool WriteLog(string content, string path) 32 { 33 return Factory.GetTextWriter(path).WriteLog(DateTime.Now.ToString("日志时间:yyyy-MM-dd HH:mm:ss fff ") + content + Environment.NewLine); 34 } 35 36 internal static void WirteLogError(Exception exception) 37 { 38 string content = string.Format("记录日志失败...消息:{0} 地址:{1} 堆栈:{2}", exception.Message, exception.TargetSite, exception.StackTrace); 39 WriteLog(content); 40 } 41 }
2.解析配置文件介绍(Config)
主要是把刚刚介绍的那几个属性解析出来
解析成Dictionary<string, ConfigSection>联系 key就是对象 type 即一个分类(列如一个异常日志)
ConfigSection : 该日志的基本信息
TypeName : 类型名称
Catalog:表名
Setting : 设置信息(数据库链接,写入数据库类型, 写入时间间隔 ,写入最大条数)
Mapping : 日志实体信息
1 internal class ConfigSection 2 { 3 internal ConfigSection(string typeName,string catalog,Setting setting,List<Mapping> mappings) 4 { 5 TypeName = typeName; 6 Catalog = catalog; 7 Setting = setting; 8 Mappings = mappings; 9 } 10 internal string TypeName { get; private set; } 11 internal string Catalog { get; private set; } 12 internal Setting Setting { get; private set; } 13 internal List<Mapping> Mappings { get; private set; } 14 }
1 internal class ConfigSection 2 { 3 internal ConfigSection(string typeName,string catalog,Setting setting,List<Mapping> mappings) 4 { 5 TypeName = typeName; 6 Catalog = catalog; 7 Setting = setting; 8 Mappings = mappings; 9 } 10 internal string TypeName { get; private set; } 11 internal string Catalog { get; private set; } 12 internal Setting Setting { get; private set; } 13 internal List<Mapping> Mappings { get; private set; } 14 }
1 Mapping
解析代码LocalXMLLoader
1 internal class LocalXMLLoader:Loader 2 { 3 private readonly string _path; 4 internal LocalXMLLoader(string path) 5 { 6 _path = path; 7 } 8 9 internal override Dictionary<string, ConfigSection> Execute() 10 { 11 Dictionary<string, ConfigSection> result = new Dictionary<string, ConfigSection>(); 12 XmlDocument doc = new XmlDocument(); 13 doc.Load(this._path); 14 XmlNode defaultSettingNode = doc.SelectSingleNode("configurations/setting"); 15 Setting defaultSetting = ParseSetting(defaultSettingNode); 16 XmlNodeList sectionNodes = doc.SelectNodes("configurations/sections/section"); 17 if (sectionNodes == null) return result; 18 foreach (XmlNode sectionNode in sectionNodes) 19 { 20 if (sectionNode.Attributes == null) continue; 21 string typeName = GetAttribute(sectionNode.Attributes["type"]); 22 string catalog = GetAttribute(sectionNode.Attributes["catalog"]); 23 Setting setting = ParseSetting(sectionNode.SelectSingleNode("setting"),defaultSetting); 24 List<Mapping> mappings = ParseMappings(sectionNode.SelectNodes("mapping")); 25 ConfigSection section = new ConfigSection(typeName, catalog, setting, mappings); 26 result.Add(section.TypeName, section); 27 } 28 return result; 29 } 30 private static Setting ParseSetting(XmlNode node) 31 { 32 if (node == null || node.Attributes == null) return null; 33 string model = GetAttribute(node.Attributes["model"]); 34 //当在maxcount分钟内有大于等于interval条数据的时候才去写入数据库 35 string maxCount = GetAttribute(node.Attributes["maxcount"]); 36 string interval = GetAttribute(node.Attributes["interval"]); 37 string writer = GetAttribute(node.Attributes["writer"]); 38 string connectionString = GetAttribute(node.Attributes["connectionstring"]); 39 return new Setting(model, maxCount, interval, writer, connectionString); 40 } 41 private static Setting ParseSetting(XmlNode node, Setting defaultSetting) 42 { 43 Setting setting = ParseSetting(node); 44 if (setting != null) 45 { 46 return new Setting( 47 string.IsNullOrWhiteSpace(setting.Model) ? defaultSetting.Model : setting.Model, 48 string.IsNullOrWhiteSpace(setting.MaxCount) ? defaultSetting.MaxCount : setting.MaxCount, 49 string.IsNullOrWhiteSpace(setting.Interval) ? defaultSetting.Interval : setting.Interval, 50 string.IsNullOrWhiteSpace(setting.Writer) ? defaultSetting.Writer : setting.Writer, 51 string.IsNullOrWhiteSpace(setting.ConnectionString) ? defaultSetting.ConnectionString : setting.ConnectionString); 52 } 53 return defaultSetting; 54 } 55 private static List<Mapping> ParseMappings(XmlNodeList nodes) 56 { 57 List<Mapping> result = new List<Mapping>(); 58 if (nodes != null) 59 { 60 foreach (XmlNode node in nodes) 61 { 62 if (node.Attributes == null) continue; 63 string property = GetAttribute(node.Attributes["property"]); 64 string name = GetAttribute(node.Attributes["name"]); 65 string format = GetAttribute(node.Attributes["format"]); 66 result.Add(new Mapping(property, name, format)); 67 } 68 } 69 return result; 70 } 71 private static string GetAttribute(XmlAttribute attr) 72 { 73 return GetAttribute(attr, string.Empty); 74 } 75 private static string GetAttribute(XmlAttribute attr, string defaultValue) 76 { 77 return attr == null ? defaultValue : attr.Value; 78 } 79 }
3.写入存储方式(Writer)
这里先暂时不考虑Context这个类型后面会讲解这个类型怎么来
写入抽象一个类型出来提供2个写入方法
单条写入
internal abstract void Execute(Context log);
批量写入
internal abstract void Execute(List<Context> logs);
DBWriter数据库写入方式
1 internal abstract class DBWriter : Writer 2 { 3 private readonly string _connectionString = string.Empty; 4 private readonly string _provider = string.Empty; 5 protected readonly string Catalog = string.Empty; 6 protected DBWriter(string provider, string connectionString, string cataLog) 7 { 8 _provider = provider; 9 _connectionString = connectionString; 10 Catalog = cataLog; 11 } 12 internal override void Execute(Context log) 13 { 14 if (log == null || log.Content == null || log.Content.Count == 0) return; 15 try 16 { 17 using (DbConnection conn = GetConnection()) 18 { 19 using (DbCommand cmd = conn.CreateCommand()) 20 { 21 PrepareInsert(cmd, log); 22 cmd.ExecuteNonQuery(); 23 } 24 } 25 } 26 catch (Exception ex) 27 { 28 LogService.WirteLogError(ex); 29 } 30 } 31 32 internal override void Execute(List<Context> logs) 33 { 34 try 35 { 36 using (DbConnection conn = GetConnection()) 37 { 38 using (DbCommand cmd = conn.CreateCommand()) 39 { 40 PrepareInsert(cmd, logs); 41 cmd.ExecuteNonQuery(); 42 } 43 } 44 } 45 catch (Exception ex) 46 { 47 LogService.WirteLogError(ex); 48 } 49 } 50 51 private DbConnection GetConnection() 52 { 53 DbProviderFactory dbf = DbProviderFactories.GetFactory(_provider); 54 DbConnection conn = dbf.CreateConnection(); 55 if (conn == null) return null; 56 conn.ConnectionString = _connectionString; 57 if (conn.State != ConnectionState.Open) 58 { 59 conn.Open(); 60 } 61 return conn; 62 } 63 protected abstract void PrepareInsert(DbCommand cmd, Context log); 64 protected abstract void PrepareInsert(DbCommand cmd, List<Context> logs); 65 }
Oracle数据库写入
1 internal class OracleWriter:DBWriter 2 { 3 internal OracleWriter(string connectionString, string catalog) : base("System.Data.OracleClient", connectionString, catalog) { } 4 protected override void PrepareInsert(DbCommand cmd, Context log) 5 { 6 const string sqlFormat = "INSERT INTO {0} ({1}) VALUES ({2})"; 7 var fields = new StringBuilder(); 8 var parameters = new StringBuilder(); 9 10 foreach (DataItem di in log.Content) 11 { 12 fields.AppendFormat("{0},", di.Name); 13 parameters.AppendFormat(":{0},", di.Name); 14 var p = cmd.CreateParameter(); 15 p.ParameterName = di.Name; 16 if (di.Value == null) 17 { 18 p.Value = System.DBNull.Value; 19 } 20 else if (di.Value is System.Enum) 21 { 22 p.Value = di.Value.GetHashCode(); 23 } 24 else 25 { 26 p.Value = di.Value; 27 } 28 cmd.Parameters.Add(p); 29 } 30 cmd.CommandText = string.Format(sqlFormat, 31 Catalog, 32 fields.Remove(fields.Length - 1, 1), 33 parameters.Remove(parameters.Length - 1, 1)); 34 } 35 36 protected override void PrepareInsert(DbCommand cmd, List<Context> logs) 37 { 38 const string sqlFormat = "INSERT INTO {0} ({1}) ({2})"; 39 const string fieldFormat = " SELECT {0} FROM DUAL UNION ALL"; 40 var fields = new StringBuilder(); 41 var parameters = new StringBuilder(); 42 int index = 1; 43 foreach (Context log in logs) 44 { 45 if (log.Content == null) continue; 46 var tempParam = new StringBuilder(); 47 foreach (var di in log.Content) 48 { 49 tempParam.AppendFormat(":{0}{1},", di.Name, index); 50 var p = cmd.CreateParameter(); 51 p.ParameterName = di.Name + index; 52 if (di.Value == null) 53 { 54 p.Value = System.DBNull.Value; 55 } 56 else if (di.Value is System.Enum) 57 { 58 p.Value = di.Value.GetHashCode(); 59 } 60 else 61 { 62 p.Value = di.Value; 63 } 64 cmd.Parameters.Add(p); 65 } 66 if (fields.Length == 0) 67 { 68 foreach (var di in log.Content) 69 { 70 fields.Append(di.Name + ","); 71 } 72 } 73 index++; 74 parameters.AppendFormat(fieldFormat, tempParam.Remove(tempParam.Length - 1, 1)); 75 } 76 cmd.CommandText = string.Format(sqlFormat, 77 Catalog, 78 fields.Remove(fields.Length - 1, 1), 79 parameters.Remove(parameters.Length - 10, 10)); 80 } 81 }
SqlService数据写入
1 internal class SqlServiceWriter:DBWriter 2 { 3 internal SqlServiceWriter(string connectionString, string cataLog) : base("System.Data.SqlClient", connectionString, cataLog) { } 4 protected override void PrepareInsert(DbCommand cmd, Context log) 5 { 6 const string sqlFormat = "INSERT INTO {0} ({1}) VALUES ({2});"; 7 StringBuilder fields = new StringBuilder(); 8 StringBuilder parameters = new StringBuilder(); 9 10 foreach (DataItem di in log.Content) 11 { 12 fields.AppendFormat("{0},", di.Name); 13 parameters.AppendFormat("@{0},", di.Name); 14 DbParameter p = cmd.CreateParameter(); 15 p.ParameterName = di.Name; 16 if (di.Value == null) 17 { 18 p.Value = DBNull.Value; 19 } 20 else if (di.Value is Enum) 21 { 22 p.Value = di.Value.GetHashCode(); 23 } 24 else 25 { 26 p.Value = di.Value; 27 } 28 cmd.Parameters.Add(p); 29 } 30 cmd.CommandText = string.Format(sqlFormat, 31 Catalog, 32 fields.Remove(fields.Length - 1, 1), 33 parameters.Remove(parameters.Length - 1, 1)); 34 } 35 36 protected override void PrepareInsert(DbCommand cmd, List<Context> logs) 37 { 38 const string sqlFormat = "INSERT INTO {0} ({1}) ({2});"; 39 const string fieldFormat = " SELECT {0} UNION ALL"; 40 StringBuilder fields = new StringBuilder(); 41 StringBuilder parameters = new StringBuilder(); 42 int index = 1; 43 foreach (Context log in logs) 44 { 45 if (log.Content == null) continue; 46 StringBuilder tempParam = new StringBuilder(); 47 foreach (DataItem di in log.Content) 48 { 49 tempParam.AppendFormat("@{0}{1},", di.Name, index); 50 DbParameter p = cmd.CreateParameter(); 51 p.ParameterName = di.Name + index; 52 if (di.Value == null) 53 { 54 p.Value = DBNull.Value; 55 } 56 else if (di.Value is Enum) 57 { 58 p.Value = di.Value.GetHashCode(); 59 } 60 else 61 { 62 p.Value = di.Value; 63 } 64 cmd.Parameters.Add(p); 65 } 66 if (fields.Length == 0) 67 { 68 foreach (DataItem di in log.Content) 69 { 70 fields.Append(di.Name + ","); 71 } 72 index++; 73 parameters.AppendFormat(fieldFormat, tempParam.Remove(tempParam.Length - 1, 1)); 74 } 75 } 76 cmd.CommandText = string.Format(sqlFormat, 77 Catalog, 78 fields.Remove(fields.Length - 1, 1), 79 parameters.Remove(parameters.Length - 10, 10)); 80 81 } 82 } 83 }
文本文件方式写入
1 internal class TextWriter:Writer 2 { 3 private const long LogFileMaxLength = 1024 * 1024 * 1; 4 private readonly string _fileName = string.Empty; 5 internal TextWriter(string fineName) 6 { 7 _fileName = fineName; 8 } 9 internal override void Execute(Context log) 10 { 11 try 12 { 13 WriteLog(GetLogContent(log) + Environment.NewLine); 14 } 15 catch (Exception ex) 16 { 17 LogService.WirteLogError(ex); 18 } 19 } 20 internal override void Execute(List<Context> logs) 21 { 22 try 23 { 24 StringBuilder sbContent = new StringBuilder(); 25 foreach (Context log in logs) 26 { 27 sbContent.AppendLine(GetLogContent(log)); 28 } 29 WriteLog(sbContent.ToString()); 30 } 31 catch (Exception ex) 32 { 33 LogService.WirteLogError(ex); 34 } 35 } 36 internal bool WriteLog(string logInfo) 37 { 38 if (string.IsNullOrWhiteSpace(logInfo)) 39 { 40 return true; 41 } 42 DateTime timeStamp = DateTime.Now; 43 string path = GetFileMainPath(timeStamp); 44 FileInfo lastFile = GetLastAccessFile(path); 45 FileStream fileStream = GetFileStream(lastFile, path, timeStamp); 46 if (fileStream == null) 47 { 48 return false; 49 } 50 try 51 { 52 StreamWriter sw = new StreamWriter(fileStream); 53 sw.BaseStream.Seek(0, SeekOrigin.End); 54 sw.Write(logInfo); 55 sw.Flush(); 56 sw.Close(); 57 } 58 catch 59 { 60 return false; 61 } 62 finally 63 { 64 fileStream.Close(); 65 fileStream.Dispose(); 66 } 67 return true; 68 } 69 private static FileInfo GetLastAccessFile(string path) 70 { 71 FileInfo result = null; 72 DirectoryInfo direcInfo = new DirectoryInfo(path); 73 //查找目录中最后的创建的文档 74 if (direcInfo.Exists) 75 { 76 FileInfo[] fileInfos = direcInfo.GetFiles(); 77 foreach (FileInfo fileinfo in fileInfos) 78 { 79 if (result == null) 80 { 81 result = fileinfo; 82 } 83 else if (result.CreationTime < fileinfo.CreationTime) 84 { 85 result = fileinfo; 86 } 87 } 88 } 89 else 90 { 91 direcInfo.Create(); 92 } 93 return result; 94 } 95 private static FileStream GetFileStream(FileInfo fileInfo, string path, DateTime timeStamp) 96 { 97 FileStream result = null; 98 // 没找到则创建一个新日志文件 99 // 如果文件大于100M,则新创建一个文件 100 // 如果文件无法打开,则新创建一个文件 101 if (fileInfo == null) 102 { 103 try 104 { 105 result = CreateFile(path, GetFileMainName(timeStamp)); 106 } 107 catch (Exception) 108 { 109 return null; 110 } 111 } 112 else if (IsOutOfFileMaxLength(fileInfo.Length)) 113 { 114 result = CreateFile(path, GetFileMainName(timeStamp)); 115 } 116 else 117 { 118 try 119 { 120 result = fileInfo.OpenWrite(); 121 } 122 catch 123 { 124 result = CreateFile(path, GetFileMainName(timeStamp)); 125 } 126 } 127 return result; 128 } 129 private static bool IsOutOfFileMaxLength(long fileLength) 130 { 131 return fileLength > LogFileMaxLength; 132 } 133 private static string GetLogContent(Context log) 134 { 135 StringBuilder result = new StringBuilder(); 136 result.AppendFormat("日志时间:{0} ", log.Time.ToString("yyyy-MM-dd HH:mm:ss fff")); 137 if (log.Content != null) 138 { 139 foreach (DataItem di in log.Content) 140 { 141 string value; 142 if (di.Value is DateTime) 143 { 144 if (di.Format == null || di.Format.Trim().Length == 0) 145 { 146 value = ((DateTime)di.Value).ToString("yyyy-MM-dd HH:mm:ss fff"); 147 } 148 else 149 { 150 value = ((DateTime)di.Value).ToString(di.Format); 151 } 152 } 153 else 154 { 155 value = (di.Value ?? "").ToString(); 156 } 157 result.AppendFormat("{0}:{1} ", di.Name, value); 158 } 159 } 160 result.AppendLine(); 161 return result.ToString(); 162 } 163 private static FileStream CreateFile(string path, string fileName) 164 { 165 return File.Create(string.Format(@"{0}\{1}.log",path,fileName)); 166 } 167 168 private string GetFileMainPath(DateTime timeStamp) 169 { 170 return Path.Combine(_fileName, timeStamp.ToString("yyyyMMdd")); 171 } 172 private static string GetFileMainName(DateTime timeStamp) 173 { 174 return timeStamp.ToString("HHmmss"); 175 } 176 }
4.写入类型(Processor)
处理方式:Immediate(即时写入)则非常简单只需要直接调用写入方法即可
1 internal class ImmediateProcessor:Processor 2 { 3 internal ImmediateProcessor(Writer.Writer writer) : base(writer) { } 4 internal override void Inject(Context log) 5 { 6 LogWriter.Execute(log); 7 } 8 }
处理方式:Queue(队列写入) 队列写入实现原理 则是新开一条线程来存储即将写入的日志 当写入满足配置文件配置的 maxcount 或者 interval 2个属性的任意一个条件则写入数据库
1 internal class QueueProcessor:Processor 2 { 3 private readonly uint _maxCount; 4 private readonly uint _interval; 5 private readonly Queue<Context> _logs; 6 private readonly object _locker = new object(); 7 private bool _stoped = true; 8 private DateTime _lastFlusTime = DateTime.Now; 9 internal QueueProcessor(Writer.Writer write, uint maxCount, uint interval) 10 :base(write) 11 { 12 _maxCount = maxCount; 13 _interval = interval; 14 _logs = new Queue<Context>(); 15 } 16 internal override void Inject(Context log) 17 { 18 lock (_locker) 19 { 20 _logs.Enqueue(log); 21 SetThread(); 22 } 23 } 24 25 private void SetThread() 26 { 27 if (!_stoped) return; 28 _stoped = false; 29 ThreadPool.QueueUserWorkItem(Run); 30 } 31 private void Run(object state) 32 { 33 while (!_stoped) 34 { 35 if (RequireFlush()) 36 { 37 FlushData(); 38 SetFlushInfo(); 39 } 40 Thread.Sleep(50); 41 } 42 } 43 private bool RequireFlush() 44 { 45 return _logs.Count >= _maxCount || IsExpired(); 46 } 47 48 private bool IsExpired() 49 { 50 return (DateTime.Now - _lastFlusTime).TotalMinutes >= _interval; 51 } 52 53 private void FlushData() 54 { 55 LogWriter.Execute(GetData()); 56 } 57 58 private List<Context> GetData() 59 { 60 List<Context> result = new List<Context>(); 61 lock (_locker) 62 { 63 while (result.Count < _maxCount && _logs.Count > 0) 64 { 65 result.Add(_logs.Dequeue()); 66 } 67 } 68 return result; 69 } 70 71 private void SetFlushInfo() 72 { 73 _lastFlusTime = DateTime.Now; 74 if (_logs.Count == 0) 75 { 76 _stoped = true; 77 } 78 } 79 }
5.服务层创建日志并调用
Allocator类来联系当前上下文
Intance属性:为单列模式 使用单列模式创建该类型对象
bool Execute(object item) 执行方法根据 item 取出配置文件信息 并且创建Context对象
Processor GetProcessor(ConfigSection section, string key) 方法根据配置文件信息创建出使用那种写入方式跟数据库
创建方式通过Factory类(工厂方法实现)
Factory
1 internal class Factory 2 { 3 internal static Processor.Processor CreateProcessor(Writer.Writer writer, Setting setting) 4 { 5 Processor.Processor result = null; 6 if (setting == null) return null; 7 switch ((setting.Model ?? "").ToLower()) 8 { 9 case "queue": 10 result = new QueueProcessor(writer, GetUnit(setting.MaxCount, 10), GetUnit(setting.Interval, 2)); 11 break; 12 case "immediate": 13 result = new ImmediateProcessor(writer); 14 break; 15 16 } 17 return result; 18 } 19 private static uint GetUnit(string value, uint defaultVaule) 20 { 21 uint result; 22 if (!uint.TryParse(value,out result)) 23 { 24 result = defaultVaule; 25 } 26 return result; 27 } 28 private static readonly Dictionary<string, Writer.Writer> Writers = new Dictionary<string, Writer.Writer>(); 29 internal static Writer.Writer CreateWriter(ConfigSection section) 30 { 31 if (section == null) return null; 32 if (section.Setting == null) return null; 33 string key = section.Setting.Writer + section.Catalog; 34 if (Writers.ContainsKey(key)) 35 { 36 return Writers[key]; 37 } 38 Writer.Writer writer = null; 39 switch ((section.Setting.Writer ?? "").ToLower()) 40 { 41 case "text": 42 writer = new TextWriter(section.Catalog); 43 break; 44 case "oracle": 45 writer = new OracleWriter(section.Setting.ConnectionString,section.Catalog); 46 break; 47 case "sqlserver": 48 writer = new SqlServiceWriter(section.Setting.ConnectionString, section.Catalog); 49 break; 50 } 51 Writers.Add(key, writer); 52 return writer; 53 } 54 private static readonly Dictionary<string, TextWriter> TextWriters = new Dictionary<string, TextWriter>(); 55 internal static TextWriter GetTextWriter(string path) 56 { 57 TextWriter writer; 58 if (TextWriters.TryGetValue(path, out writer)) return writer; 59 writer = new TextWriter(path); 60 TextWriters.Add(path, writer); 61 return writer; 62 } 63 internal static Loader CreateLoader() 64 { 65 //return new LocalXMLLoader(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LogConfig.xml")); 66 return new LocalXMLLoader(System.Configuration.ConfigurationManager.AppSettings["LogConfig"]); 67 } 68 }
1 /// <summary> 2 /// 日志处理分配器 3 /// </summary> 4 internal class Allocator 5 { 6 private static readonly object InstanceLocker = new object(); 7 private static Allocator _intance; 8 9 /// <summary> 10 /// 分配器实例 11 /// </summary> 12 internal static Allocator Intance 13 { 14 get 15 { 16 if (_intance == null) 17 { 18 lock (InstanceLocker) 19 { 20 if (_intance == null) 21 { 22 _intance = new Allocator(); 23 } 24 } 25 } 26 return _intance; 27 } 28 } 29 30 private readonly Dictionary<string, Processor.Processor> _processors; 31 private Allocator() { 32 _processors = new Dictionary<string, Processor.Processor>(); 33 } 34 /// <summary> 35 /// 分配日志 36 /// </summary> 37 /// <param name="item">日志信息</param> 38 /// <returns>成功?true:false</returns> 39 internal bool Execute(object item) 40 { 41 DateTime logTime = DateTime.Now; 42 string key = item.GetType().FullName; 43 ConfigSection section = ConfigCollections.Instance[key]; 44 if (section == null) 45 { 46 LogService.WriteLog("未找到[" + key + "]的配置信息"); 47 } 48 else { 49 Processor.Processor processor = GetProcessor(section, key); 50 if (processor == null) 51 { 52 LogService.WriteLog("未找到日志[" + key + "的处理器"); 53 } 54 else 55 { 56 try 57 { 58 Context context = new Context(logTime, Parser.Execute(item, section.Mappings)); 59 processor.Inject(context); 60 return true; 61 } 62 catch (Exception ex) 63 { 64 LogService.WirteLogError(ex); 65 } 66 } 67 } 68 return false; 69 } 70 private Processor.Processor GetProcessor(ConfigSection section, string key) 71 { 72 Processor.Processor processor = null; 73 if (_processors.ContainsKey(key)) 74 { 75 return _processors[key]; 76 } 77 lock (_processors) 78 { 79 if (_processors.ContainsKey(key)) 80 { 81 return _processors[key]; 82 } 83 var writer = Factory.CreateWriter(section); 84 if (writer != null) 85 { 86 processor = Factory.CreateProcessor(writer, section.Setting); 87 } 88 _processors.Add(key, processor); 89 } 90 return processor; 91 } 92 }
6.DEMO
记录异常日志类型为列子 配置文件 如1.
异常实体类ExceptionLog
1 public class ExceptionLog 2 { 3 public ExceptionLog(string message, string source, string targetSite, string stackTrace, DateTime errorTime, string remark) 4 { 5 this.Message = message; 6 this.Source = source; 7 this.TargetSite = targetSite; 8 this.StackTrace = stackTrace; 9 this.ErrorTime = errorTime; 10 this.Remark = remark; 11 } 12 /// <summary> 13 /// 消息 14 /// </summary> 15 public string Message { get; private set; } 16 /// <summary> 17 /// 程序集或对象的名称 18 /// </summary> 19 public string Source { get; private set; } 20 /// <summary> 21 /// 引发异常的方法 22 /// </summary> 23 public string TargetSite { get; private set; } 24 /// <summary> 25 /// 堆栈信息 26 /// </summary> 27 public string StackTrace { get; private set; } 28 /// <summary> 29 /// 错误发生时间 30 /// </summary> 31 public DateTime ErrorTime { get; private set; } 32 /// <summary> 33 /// 备注 34 /// </summary> 35 public string Remark { get; private set; } 36 }
写入异常日志
1 /// <summary> 2 /// 记录日志 3 /// </summary> 4 public static class LogService 5 { 6 /// <summary> 7 /// 记录异常日志 8 /// </summary> 9 /// <param name="ex">异常信息</param> 10 public static void SaveExceptionLog(Exception ex) 11 { 12 SaveExceptionLog(ex, DateTime.Now); 13 } 14 /// <summary> 15 /// 记录异常日志 16 /// </summary> 17 /// <param name="ex">异常信息</param> 18 /// <param name="errorTime">发生异常时间</param> 19 public static void SaveExceptionLog(Exception ex, DateTime errorTime) 20 { 21 SaveExceptionLog(ex, errorTime, string.Empty); 22 } 23 /// <summary> 24 /// 记录异常日志 25 /// </summary> 26 /// <param name="ex">异常信息</param> 27 /// <param name="errorTime">发生异常时间</param> 28 /// <param name="remark">备注信息</param> 29 public static void SaveExceptionLog(Exception ex, DateTime errorTime, string remark) 30 { 31 try 32 { 33 ExceptionLog log = new ExceptionLog(ex.Message, 34 ex.Message, 35 ex.TargetSite == null ? string.Empty : ex.TargetSite.ToString(), 36 ex.StackTrace, 37 errorTime, 38 remark); 39 Logger.LogService.WriteLog(log); 40 } 41 catch 42 { 43 return; 44 } 45 } 46 /// <summary> 47 /// 记录操作日志 48 /// </summary> 49 /// <param name="log">日志详细内容</param> 50 public static void SaveOpetationLog(OperationLog log) 51 { 52 try 53 { 54 Logger.LogService.WriteLog(log); 55 } 56 catch 57 { 58 59 } 60 } 61 }
7.结语
如果上面讲解中没有列出的类或者方法可以到下载下面的附件
8.提供源代码下载