最近公司有个需求,要对业务日志进行记录并根据日志排查问题,以前都是使用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 }
View Code
测试程序用到的自定义日志类:
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 }