最近公司有個需求,要對業務日志進行記錄並根據日志排查問題,以前都是使用log4net之類的日志組件來記錄到文件,這種方式已經不能滿足業務的需要,因為日志文件會很大,即使進行分割后,查找也是很不方便,何況現在項目基本都是分布式,會有多台應用服務器,那么就需要把多台服務器上的日志弄到一起,十分的麻煩,經過選擇后ELK進入視線,測試環境也搭建了一套,現在唯一的問題就是怎么把多台服務器上的日子泵出到elstaticsearch中,我們的應用服務器都是windows,所以需要在每一台應用服務器上安裝一個服務,如:NXlog之類的,經過考慮覺得這種方式太麻煩,所以決定把日志先記錄到MongoDb,先實現簡單的日志查詢,再統一從MongoDb將數據泵出到elstaticsearch中,思路有了,開始動手測試。
第一步,插入測試數據,MongoDb數據庫我是安裝在本地一個linux虛擬機里,插入1000000條數據耗時8分鍾,有興趣的童鞋自己測試一下,用來存儲日志完全沒有問題,廢話不多說了,上代碼:
1 static void Main(string[] args) 2 { 3 try 4 { 5 #region 插入測試數據 6 //var sw = new Stopwatch(); 7 //sw.Start(); 8 //string tableName = "InsuranceLog"; 9 //for (var i = 0; i < 1000000; i++) 10 //{ 11 // var lb = new LogBase<InsuranceLog>() 12 // { 13 // Message = new InsuranceLog 14 // { 15 // BusinessKey = i.ToString(), 16 // BusinessName = "政策查詢" + i, 17 // BusinessParameters = "根據實際需要組織<xml><OrderId>AutoHome" + i + "</OrderId></xml>" 18 // } 19 // }; 20 21 // InsertOneLogToMongoDbAsync(lb, tableName); 22 //} 23 //sw.Stop(); 24 //Console.WriteLine("插入100000條數據耗時:" + sw.ElapsedMilliseconds + "ms"); 25 #endregion 26 27 #region 根據條件從1000000條數據中獲取指定數據 28 var sw = new Stopwatch(); 29 sw.Start(); 30 var obj = GetList(); 31 sw.Stop(); 32 Console.WriteLine("從100000條數據獲取指定數據耗時:" + sw.ElapsedMilliseconds + "ms"); 33 foreach (var o in obj) 34 { 35 if (o.Message != null) 36 { 37 Console.WriteLine("調用時間:"+o.CallTime); 38 Console.WriteLine("業務key:" + o.Message.BusinessKey); 39 Console.WriteLine("業務名稱:" + o.Message.BusinessName); 40 Console.WriteLine("業務參數:" + o.Message.BusinessParameters); 41 } 42 } 43 #endregion 44 Console.ReadKey(); 45 } 46 catch (Exception ex) 47 { 48 throw; 49 } 50 } 51 52 53 /// <summary> 54 /// 從MongoDb 獲取數據 55 /// </summary> 56 /// <returns></returns> 57 static List<LogBase<InsuranceLog>> GetList() 58 { 59 try 60 { 61 var client = new MongoClient("mongodb://192.168.21.129:27017"); 62 var database = client.GetDatabase("logs"); 63 var collection = database.GetCollection<LogBase<InsuranceLog>>("InsuranceLog"); 64 var b = (from x in collection.AsQueryable() 65 where x.CallTime.StartsWith("201604281414") 66 && x.CallTime.EndsWith("000") 67 select x).ToList(); 68 return b; 69 } 70 catch (Exception ex) 71 { 72 throw; 73 } 74 } 75 76 77 /// <summary> 78 /// 插入單條數據 79 /// </summary> 80 /// <typeparam name="T"></typeparam> 81 /// <param name="t"></param> 82 /// <param name="name"></param> 83 static async Task InsertOneLogToMongoDbAsync<T>(T t, string name) 84 { 85 try 86 { 87 var client = new MongoClient("mongodb://192.168.21.129:27017"); 88 var database = client.GetDatabase("logs"); 89 var collection = database.GetCollection<T>(name); 90 await collection.InsertOneAsync(t); 91 } 92 catch (Exception ex) 93 { 94 throw; 95 } 96 }
主要測試點在查詢上,要根據條件快速檢索出需要的數據,我測試了一下,單條數據大概是800ms左右,我的查詢條件取出來38條數據,耗時842ms,

重點:日志基類,擴展性很好,支持自定義實體類
1 /// <summary> 2 /// 日志基類 3 /// </summary> 4 [BsonIgnoreExtraElements] 5 public class LogBase<T> 6 { 7 public LogBase() 8 { 9 CallTime = DateTime.Now.ToString("yyyyMMddHHmmssfff"); 10 SerialNo = Guid.NewGuid().ToString("N"); 11 ClientType = "1"; 12 Message = default(T); 13 var myEntry = Dns.GetHostEntry(Dns.GetHostName()); 14 var address = myEntry.AddressList.FirstOrDefault(e => e.AddressFamily.ToString().Equals("InterNetwork")); 15 if (address == null) return; 16 var ip = address.ToString(); 17 HostIp = ip; 18 } 19 20 /// <summary> 21 /// 調用時間,格式:yyyyMMddHH24mmss 22 /// </summary> 23 public string CallTime { get; private set; } 24 25 /// <summary> 26 /// 消息序列號 UUID 27 /// </summary> 28 public string SerialNo { get; private set; } 29 30 /// <summary> 31 /// 客戶端IP地址 32 /// </summary> 33 public string HostIp { get; private set; } 34 35 /// <summary> 36 /// 客戶端類型:1:pc 2:手機 37 /// </summary> 38 public string ClientType { get; private set; } 39 40 /// <summary> 41 /// 業務信息 42 /// </summary> 43 public T Message { get; set; } 44 45 }
測試程序用到的自定義日志類:
1 public class InsuranceLog 2 { 3 /// <summary> 4 /// 當前登錄用戶 5 /// </summary> 6 public string UserName { get; set; } 7 8 /// <summary> 9 /// 業務key 10 /// </summary> 11 public string BusinessKey { get; set; } 12 13 /// <summary> 14 /// 業務名稱 如:查詢政策 下訂單 查看訂單 15 /// </summary> 16 public string BusinessName { get; set; } 17 18 /// <summary> 19 /// 業務參數 20 /// </summary> 21 public string BusinessParameters { get; set; } 22 }
未完待續
