利用队列和定时器构造的一种日志记录模型实现
来源:互联网 发布:淘宝买家钻石等级 编辑:程序博客网 时间:2024/06/16 12:20
软件系统在运行过程中,会产生大量的运行时中间数据,中间数据是整个数据流向和异常后的回溯,一个好的日志记录系统,能记录下整个软件运行周期内的所有相关中间数据流。
日志记录系统首先要保证的是与软件的正常运行无关性,他不会随着软件异常的抛出,而崩溃或阻塞正常的系统运行,日志系统还要高效性,不能因为记录日志影响系统的整体资源调度。
此模型的设计思路是,异常消息记录队列+周期性处理定时器+消息关闭回调消息中心,所有的日志,统一先压入异常消息记录队列,周期性处理定时器触发后,负责将消息队列整体锁定,更换队列的处理引用地址,在定时器处理线程栈上,进行数据的写入处理,因为是通过定时器周期性的写入数据到存储介质,在软件关闭时刻可能存在还未写入存储介质的数据,因此需要消息中心的回调处理,进行数据的收尾保存。
此模型的设计,简单易于实现,但是也存在很大的弊端是,在高并发场合的写入会存在很高的锁争用。定时器控制写入到存储介质,吞吐和效率不好调整。如果存在日志保存到比较慢速的介质中,缓存不够。
/// <summary> ///SQL操作日志记录服务 /// </summary> internal static class SQLLogService { /// <summary> /// 线程互斥锁 /// </summary> private static object syncObj = new object(); /// <summary> /// 写入锁 /// </summary> private static object writeLock = new object(); /// <summary> /// 日志记录消息队列 /// </summary> private static Queue<SQLLogMessage> logMessageQueue = new Queue<SQLLogMessage>(); /// <summary> /// 处理定时器 /// </summary> private static System.Timers.Timer timer = null; /// <summary> /// 消息中心停止通知 /// </summary> private static MessageCenterStopCallBack stopCallBack = null; /// <summary> /// 启动日志记录服务 /// </summary> public static void Start() { if (timer == null) { timer = new System.Timers.Timer(); timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Interval = SQLLogFactory.Config.LogPeriod;//日志保存周期,三分钟 timer.Start(); if (stopCallBack == null) { stopCallBack = new MessageCenterStopCallBack(stopNotify); MessageCenterManage.Register(typeof(SQLLogService).FullName, stopCallBack); } } } /// <summary> /// 回调处理函数 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { List<SQLLogMessage> tempList = null; lock (syncObj) { try { Int32 count = logMessageQueue.Count; if (count > 0) { tempList = new List<SQLLogMessage>(); for (int i = 0; i < count; i++) { tempList.Add(logMessageQueue.Dequeue()); } } } catch { } } if (tempList != null && tempList.Count > 0) { lock (writeLock) { try { Dictionary<string, StreamWriter> dic = new Dictionary<string, StreamWriter>(); string filePath = string.Format("{0}\\SQLLog\\{1}\\",SQLLogFactory.Config.LogPath, DateTime.Now.ToString("yyyyMMdd")); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } //开始记录日志数据 for (int i = 0; i < tempList.Count; i++) { SQLLogMessage logMessage = tempList[i]; string fileFullName = string.Format("{0}{1}", filePath, logMessage.FileName); if (dic.ContainsKey(fileFullName)) { StreamWriter sw = dic[fileFullName]; sw.WriteLine(logMessage.Message); } else { StreamWriter sw = new StreamWriter(fileFullName, true); dic[fileFullName] = sw; sw.WriteLine(logMessage.Message); } } foreach (var item in dic.Keys) { StreamWriter sw = dic[item]; sw.Flush(); sw.Close(); } dic.Clear(); } catch { } } } } /// <summary> /// 停止日志记录服务 /// </summary> public static void Stop() { List<SQLLogMessage> tempList = null; lock (syncObj) { Int32 count = logMessageQueue.Count; if (count > 0) { tempList = new List<SQLLogMessage>(); for (int i = 0; i < count; i++) { tempList.Add(logMessageQueue.Dequeue()); } } } if (tempList != null && tempList.Count > 0) { lock (writeLock) { try { Dictionary<string, StreamWriter> dic = new Dictionary<string, StreamWriter>(); string filePath = string.Format("{0}\\SQLLog\\{1}\\", SQLLogFactory.Config.LogPath, DateTime.Now.ToString("yyyyMMdd")); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } //开始记录日志数据 for (int i = 0; i < tempList.Count; i++) { SQLLogMessage logMessage = tempList[i]; string fileFullName = string.Format("{0}{1}", filePath, logMessage.FileName); if (dic.ContainsKey(fileFullName)) { StreamWriter sw = dic[fileFullName]; sw.WriteLine(logMessage.Message); } else { StreamWriter sw = new StreamWriter(fileFullName, true); dic[fileFullName] = sw; sw.WriteLine(logMessage.Message); } } foreach (var item in dic.Keys) { StreamWriter sw = dic[item]; sw.WriteLine("停止日志记录"); sw.Flush(); sw.Close(); } dic.Clear(); } catch { } } } if (timer != null) { if (timer.Enabled == true) { timer.Stop(); } timer = null; } } /// <summary> /// 要记录的日志数据压队队列 /// </summary> /// <param name="logType"></param> /// <param name="message"></param> public static void LogSystem(string header,string message) { try { SQLLogMessage logMessage = new SQLLogMessage(); logMessage.FileName = string.Format("{0}.Log", header); logMessage.Message = string.Format("{0} {1}", DateTime.Now.ToString(), message); lock (syncObj) { logMessageQueue.Enqueue(logMessage); } if (timer == null) { timer = new System.Timers.Timer(); timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Interval = SQLLogFactory.Config.LogPeriod;//日志保存周期,三分钟 timer.Start(); if (stopCallBack == null) { stopCallBack = new MessageCenterStopCallBack(stopNotify); MessageCenterManage.Register(typeof(SQLLogService).FullName, stopCallBack); } } else if (timer.Enabled == false) { timer.Start(); if (stopCallBack == null) { stopCallBack = new MessageCenterStopCallBack(stopNotify); MessageCenterManage.Register(typeof(SQLLogService).FullName, stopCallBack); } } } catch { } } /// <summary> /// 获取消息中心的通知 /// </summary> /// <param name="signal"></param> private static void stopNotify(bool signal) { if (signal == true) { Stop(); } } /// <summary> /// 获取日志记录服务的状态 /// </summary> /// <returns></returns> public static bool GetLogServiceStatus() { if (timer == null) { return false; } else { if (timer.Enabled == true) { return true; } else { return false; } } } }
0 0
- 利用队列和定时器构造的一种日志记录模型实现
- 利用Annotation和Aop实现日志记录
- 一种简便的计时器和日志记录方案
- 利用触发器实现日志记录
- 利用Spring AOP实现业务和异常日志记录
- 利用Java Annotation 和 Spring AOP实现在Controller层面的操作日志记录
- 利用Global.asax的Application_Error实现错误记录,错误日志
- 双队列的一种实现
- 优先级队列的一种实现
- 双队列的一种实现
- 优先队列的一种实现
- 一种Future模型的实现
- PHP和MySQL实现 定时器+消息队列
- 工作日志记录:关于脉脉这款应用的默认用户头像的一种实现方法
- VC利用console调试和记录日志
- 基于ACE的定时器队列实现
- 一种可并发读写的队列实现
- 一种简单无锁队列的实现
- Navicat for mysql 远程连接 mySql数据库10061错误问题
- Java编程思想(九) —— 持有对象(下)
- 8.7-硬币组合
- UVALive 5792 Diccionário Portuñol(字典树)
- C# dataGridView控件中加入comboBox控件及注意事项
- 利用队列和定时器构造的一种日志记录模型实现
- Android手势源码浅析-----手势绘制(GestureOverlayView)
- 15--linux 网络编程基础
- 八大排序
- CodeForces-131A-cAPS lOCK
- java网络编程—读取html存储到文件中
- Sqrt(x)
- C++实现将十进制数转换为小于等于九的任意进制
- 在32位处理器上指针的长度为4字节,为什么是4字节,而不是16字节,或者32字节