1:背景
最近公司说,咱们业务系统那么多,每个系统都在写自己的日志,不方便查看和管理。
于是,想搞个日志收集系统。
2:构思
3:实现
a):收集服务
收集服务采用ServiceStack框架,提供web api 的方式访问。
客户端调用服务,直接把日志信息丢到消息队列中
public AopResult<Int32> Get(LogRequest obj) { if (obj == null) return AopResult.Fail<Int32>("参数不正确!"); if (string.IsNullOrEmpty(obj.AppNo)) return AopResult.Fail<Int32>("请提供应用编号!"); if (string.IsNullOrEmpty(obj.Tag)) return AopResult.Fail<Int32>("请提供应用标签!"); if (string.IsNullOrEmpty(obj.Content)) return AopResult.Fail<Int32>("请提供日志内容!"); LogQueueHelper.EnQueue(ParserImp.Parser(obj)); return AopResult.Success(0); }
b):读取日志并创建写入任务
考虑到日志量过大,需要分表的操作,因此,在日志系统中,创建一个基表。
基表的数据包括,日志应用,标签,队列名,表名,创建日期,是否启用等信息
public class QueueKey { /// <summary> /// MongoDB 默认主键 /// </summary> public string _id { get; set; } /// <summary> /// 队列名 /// </summary> public string Key { get; set; } /// <summary> /// 应用 /// </summary> public string AppNo { get; set; } /// <summary> /// 标签 /// </summary> public string Tag { get; set; } /// <summary> /// 当前集合名称 /// </summary> public string CollectionName { get; set; } /// <summary> /// 是否启用 /// </summary> public bool Enabled { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime CreateTime { get; set; } }
创建一个任务,定时执行从队列中读取日志信息,并根据基表数据(缓存中),创建写入。并把写入任务放入到任务队列中。
public static void FlushLog() { while (true) { try { if (LogQueueHelper.QueueKeys.Any()) { //判断是否需要分库 var needRe = DateTime.Now.ToString("dd") == "01"; for (var i = 0; i < LogQueueHelper.QueueKeys.Count; i++) { var queueKey = LogQueueHelper.QueueKeys[i]; if (needRe) queueKey = DbHelper.RefreshQueueKey(queueKey); var queue = LogQueueHelper.Logs[queueKey.Key]; var length = queue.Count; var m = 0; var lst = new List<LogContent>(); while (m < length) { m++; lst.Add(queue.Dequeue()); } TaskHelper.AddTask(() => DbHelper.Insert(lst, queueKey)); } } } finally { Thread.Sleep(Config.QueueConfig.QueueSleep); } } }
c):执行日志写入任务
创建一个任务集合,每隔2S钟,从任务队列中添加一个任务到集合,上限为5个。
在添加任务到集合之前,判断集合中的任务,如果大于等于5个,则判断准备移除集合中已完成的任务。移除失败,跳出循环,继续下次执行。移除成功,则从队列中,取出下一个任务,启动后,添加到集合中
public static void RunTask() { while (true) { Thread.Sleep(2 * 1000); if (RunTasks.Count >= 5) { var task = RunTasks.FirstOrDefault(p => p.IsCompleted); if (task == null) continue; task.Dispose(); RunTasks.Remove(task); } if (QueueTasks.Count > 0) { var task = QueueTasks.Dequeue(); task.Start(); RunTasks.Add(task); } } }
4:结束
这是一个简陋的日志收集系统,欢迎大神拍砖,让我改进。