开发者社区> 技术小牛人> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil

简介:
+关注继续查看

封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,代码比较简单,主要是把MongoTarget的配置、FileTarget的配置集成到类中,同时利用缓存依赖来判断是否需要重新创建Logger类,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
using NLog;
using NLog.Config;
using NLog.Mongo;
using NLog.Targets;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Collections.Concurrent;
using NLog.Targets.Wrappers;
 
/// <summary>
/// 日志工具类(基于NLog.Mongo组件)
/// Author:左文俊
/// Date:2017/12/11
/// </summary>
public class LogUtil
{
    private NLog.Logger _Logger = null;
    private const string cacheKey_NLogConfigFlag = "NLogConfigFlag";
    private const string defaultMongoDbName = "SysLog";
    private static readonly object syncLocker = new object();
    private static readonly ConcurrentDictionary<string, LogUtil> cacheLogUitls = new ConcurrentDictionary<string, LogUtil>();
    private string loggerCacheDependencyFilePath = "";
    private bool needWriteLogToFile = true;
    private string mongoDbName = defaultMongoDbName;
    private string mongoDbCollectionName = "";
    private bool asyncWriteLog = true;
 
    public static LogUtil GetInstance(string mongoDbCollName, string loggerCacheDependencyFilePath = nullbool needWriteLogToFile = true)
    {
        string key = string.Format("{0}_{1}", defaultMongoDbName, mongoDbCollName);
        return cacheLogUitls.GetOrAdd(key, new LogUtil()
        {
            LoggerCacheDependencyFilePath = string.IsNullOrEmpty(loggerCacheDependencyFilePath) ? HttpContext.Current.Server.MapPath("~/Web.config") : loggerCacheDependencyFilePath,
            NeedWriteLogToFile = needWriteLogToFile,
            MongoDbName = defaultMongoDbName,
            MongoDbCollectionName = mongoDbCollName
        });
    }
    public string LoggerCacheDependencyFilePath
    {
        get
        {
            return loggerCacheDependencyFilePath;
        }
        set
        {
            if (!File.Exists(value))
            {
                throw new FileNotFoundException("日志配置缓存依赖文件不存在:" + value);
            }
            string oldValue = loggerCacheDependencyFilePath;
            loggerCacheDependencyFilePath = value;
            PropertyChanged(oldValue, loggerCacheDependencyFilePath);
        }
    }
 
    public bool NeedWriteLogToFile
    {
        get
        {
            return needWriteLogToFile;
        }
        set
        {
            bool oldValue = needWriteLogToFile;
            needWriteLogToFile = value;
            PropertyChanged(oldValue, needWriteLogToFile);
        }
    }
 
    public string MongoDbCollectionName
    {
        get
        {
            return mongoDbCollectionName;
        }
        set
        {
            string oldValue = mongoDbCollectionName;
            mongoDbCollectionName = value;
            PropertyChanged(oldValue, mongoDbCollectionName);
        }
    }
 
    /// <summary>
    /// 同一个项目只会用一个DB,故不对外公开,取默认DB
    /// </summary>
    private string MongoDbName
    {
        get
        {
            return mongoDbName;
        }
        set
        {
            string oldValue = mongoDbName;
            mongoDbName = value;
            PropertyChanged(oldValue, mongoDbName);
        }
    }
 
    public bool AsyncWriteLog
    {
        get
        {
            return asyncWriteLog;
        }
        set
        {
            bool oldValue = asyncWriteLog;
            asyncWriteLog = value;
            PropertyChanged(oldValue, asyncWriteLog);
        }
    }
 
 
    private void PropertyChanged<T>(T oldValue, T newValue) where T : IEquatable<T>
    {
        if (!oldValue.Equals(newValue) && _Logger != null)
        {
            lock (syncLocker)
            {
                _Logger = null;
            }
        }
    }
 
    private Logger GetLogger()
    {
 
        if (_Logger == null || HttpRuntime.Cache[cacheKey_NLogConfigFlag] == null)
        {
            lock (syncLocker)
            {
                if (_Logger == null || HttpRuntime.Cache[cacheKey_NLogConfigFlag] == null)
                {
                    string mongoDbConnectionSet = ConfigUtil.GetAppSettingValue("MongoDbConnectionSet");
                    if (!string.IsNullOrEmpty(mongoDbConnectionSet))
                    {
                        mongoDbConnectionSet = AESDecrypt(mongoDbConnectionSet);//解密字符串,若未加密则无需解密
                    }
 
                    LoggingConfiguration config = new LoggingConfiguration();
 
                    #region 配置MONGODB的日志输出对象
 
                    try
                    {
                        MongoTarget mongoTarget = new MongoTarget();
                        mongoTarget.ConnectionString = mongoDbConnectionSet;
                        mongoTarget.DatabaseName = mongoDbName;
                        mongoTarget.CollectionName = mongoDbCollectionName;
                        mongoTarget.IncludeDefaults = false;
                        AppendLogMongoFields(mongoTarget.Fields);
 
                        Target mongoTargetNew = mongoTarget;
                        if (AsyncWriteLog)
                        {
                            mongoTargetNew = WrapWithAsyncTargetWrapper(mongoTarget);//包装为异步输出对象,以便实现异步写日志
                        }
 
                        LoggingRule rule1 = new LoggingRule("*", LogLevel.Debug, mongoTargetNew);
                        config.LoggingRules.Add(rule1);
                    }
                    catch
                    { }
 
                    #endregion
 
                    #region 配置File的日志输出对象
 
                    if (NeedWriteLogToFile)
                    {
                        try
                        {
                            FileTarget fileTarget = new FileTarget();
                            fileTarget.Layout = @"[${date}] <${threadid}> - ${level} - ${event-context:item=Source} - ${event-context:item=UserID}: ${message};
                                                  StackTrace:${stacktrace};Other1:${event-context:item=Other1};Other2:${event-context:item=Other2};Other3:${event-context:item=Other3}";
 
                            string procName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
                            fileTarget.FileName = "${basedir}/Logs/" + procName + ".log";
                            fileTarget.ArchiveFileName = "${basedir}/archives/" + procName + ".{#}.log";
                            fileTarget.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence;
                            fileTarget.ArchiveAboveSize = 1024 * 1024 * 10;
                            fileTarget.ArchiveDateFormat = "yyyyMMdd";
                            fileTarget.ArchiveEvery = FileArchivePeriod.Day;
                            fileTarget.MaxArchiveFiles = 30;
                            fileTarget.ConcurrentWrites = true;
                            fileTarget.KeepFileOpen = false;
                            fileTarget.Encoding = System.Text.Encoding.UTF8;
 
                            Target fileTargetNew = fileTarget;
                            if (AsyncWriteLog)
                            {
                                fileTargetNew = WrapWithAsyncTargetWrapper(fileTarget);//包装为异步输出对象,以便实现异步写日志
                            }
 
                            LoggingRule rule2 = new LoggingRule("*", LogLevel.Debug, fileTargetNew);
                            config.LoggingRules.Add(rule2);
                        }
                        catch
                        { }
                    }
 
                    #endregion
 
 
                    LogManager.Configuration = config;
 
                    _Logger = LogManager.GetCurrentClassLogger();
 
                    HttpRuntime.Cache.Insert(cacheKey_NLogConfigFlag, "Nlog"new System.Web.Caching.CacheDependency(loggerCacheDependencyFilePath));
                }
            }
        }
 
        return _Logger;
 
    }
 
    private void AppendLogMongoFields(IList<MongoField> mongoFields)
    {
        mongoFields.Clear();
        Type logPropertiesType = typeof(SysLogInfo.LogProperties);
        foreach (var pro in typeof(SysLogInfo).GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (pro.PropertyType == logPropertiesType) continue;
 
            string layoutStr = string.Empty; //"${event-context:item=" + pro.Name + "}";
            if (pro.Name.Equals("ThreadID") || pro.Name.Equals("Level") || pro.Name.Equals("MachineName"))
            {
                layoutStr = "${" + pro.Name.ToLower() + "}";
            }
            else if (pro.Name.Equals("LogDT"))
            {
                layoutStr = "${date:format=yyyy-MM-dd HH\\:mm\\:ss}";
            }
            else if (pro.Name.Equals("Msg"))
            {
                layoutStr = "${message}";
            }
 
            if (!string.IsNullOrEmpty(layoutStr))
            {
                mongoFields.Add(new MongoField(pro.Name, layoutStr, pro.PropertyType.Name));
            }
        }
    }
 
    private Target WrapWithAsyncTargetWrapper(Target target)
    {
        var asyncTargetWrapper = new AsyncTargetWrapper();
        asyncTargetWrapper.WrappedTarget = target;
        asyncTargetWrapper.Name = target.Name;
        target.Name = target.Name + "_wrapped";
        target = asyncTargetWrapper;
        return target;
    }
 
 
    private LogEventInfo BuildLogEventInfo(LogLevel level, string msg, string source, string uid, string detailTrace = nullstring other1 = nullstring other2 = nullstring other3 = null)
    {
        var eventInfo = new LogEventInfo();
        eventInfo.Level = level;
        eventInfo.Message = msg;
        eventInfo.Properties["DetailTrace"] = detailTrace;
        eventInfo.Properties["Source"] = source;
        eventInfo.Properties["Other1"] = other1;
        eventInfo.Properties["Other2"] = other2;
        eventInfo.Properties["Other3"] = other3;
 
        eventInfo.Properties["UserID"] = uid;
 
        return eventInfo;
    }
 
    public void Info(string msg, string source, string uid, string detailTrace = nullstring other1 = nullstring other2 = nullstring other3 = null)
    {
        try
        {
            var eventInfo = BuildLogEventInfo(LogLevel.Info, msg, source, uid, detailTrace, other1, other2, other3);
            var logger = GetLogger();
            logger.Log(eventInfo);
        }
        catch
        { }
    }
 
    public void Warn(string msg, string source, string uid, string detailTrace = nullstring other1 = nullstring other2 = nullstring other3 = null)
    {
        try
        {
            var eventInfo = BuildLogEventInfo(LogLevel.Warn, msg, source, uid, detailTrace, other1, other2, other3);
 
            var logger = GetLogger();
            logger.Log(eventInfo);
        }
        catch
        { }
    }
 
 
    public void Error(string msg, string source, string uid, string detailTrace = nullstring other1 = nullstring other2 = nullstring other3 = null)
    {
        try
        {
            var eventInfo = BuildLogEventInfo(LogLevel.Error, msg, source, uid, detailTrace, other1, other2, other3);
 
            var logger = GetLogger();
            logger.Log(eventInfo);
        }
        catch
        { }
    }
 
    public void Error(Exception ex, string source, string uid, string other1 = nullstring other2 = nullstring other3 = null)
    {
        try
        {
            var eventInfo = BuildLogEventInfo(LogLevel.Error, ex.Message, source, uid, ex.StackTrace, other1, other2, other3);
 
            var logger = GetLogger();
            logger.Log(eventInfo);
        }
        catch
        { }
    }
 
    public void Log(LogLevel level, string msg, string source, string uid, string detailTrace = nullstring other1 = nullstring other2 = nullstring other3 = null)
    {
        try
        {
            var eventInfo = BuildLogEventInfo(level, msg, source, uid, detailTrace, other1, other2, other3);
            var logger = GetLogger();
            logger.Log(eventInfo);
        }
        catch
        { }
    }
 
 
    public class SysLogInfo
    {
        public DateTime LogDT { getset; }
 
        public int ThreadID { getset; }
 
        public string Level { getset; }
 
        public string Msg { getset; }
 
        public string MachineName { getset; }
 
        public LogProperties Properties { getset; }
 
        public class LogProperties
        {
            public string Source { getset; }
 
            public string DetailTrace { getset; }
 
            public string UserID { getset; }
 
            public string Other1 { getset; }
 
            public string Other2 { getset; }
 
            public string Other3 { getset; }
        }
    }
 
 
}

封装这个日志工具类的目的就是为了保证日志格式的统一,同时可以快速的复制到各个项目中使用,而省去需要配置文件或因配置文件修改导致日志记录信息不一致的情况。

从代码中可以看出,若一旦属性发生改变,则缓存标识会失效,意味着会重新生成Logger对象,这样保证了Logger时刻与设置的规则相同。

另一点就是异步日志记录功能AsyncWriteLog,如果是基于配置文件,则只需要更改配置文件targets中配置async="true"即为异步。默认或写false都为同步,而代码上如何实现异步网上并没有介绍,我通过分析NLOG源代码找到关键点,即通过AsyncTargetWrapper异步目标包裹器来包装一次即可。

本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/8641403.html ,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
网络环境查看命令:ifconfig、ifup、ifdown、route、netstat、ss
一、ifconfig ifconfig命令被用于配置和显示Linux内核中网络接口的网络参数。用ifconfig命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。 1. 安装 若系统默认没有ifconfig命令,则使用下面命令进行安装。
171 0
Newtonsoft.Json C#Json序列化和反序列化工具的使用、类型方法大全
Newtonsoft.Json C#Json序列化和反序列化工具的使用、类型方法大全
124 0
SAP QM 事务代码QE01录入结果后回车,为啥不弹出Manual Valuation窗口?
SAP QM 事务代码QE01录入结果后回车,为啥不弹出Manual Valuation窗口?
32 0
mysql全文索引FULLTEXT的哈希与BTREE方法对比
mysql全文索引FULLTEXT的哈希与BTREE方法对比
113 0
基于Scheduled SQL的log4j日志异常事件过滤与分析
采用SLS提供的Scheduled SQL功能,对log4j ERROR日志进行处理并制作可视化报表
342 0
基于Log4j完成定时创建和删除日志的方法
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 Log4j作为常用的日志生成工具,其清除日志的策略却十分有限。只有在RollingFileAppender中可以通过设置MaxFileSize和maxBackupIndex属性来指定要保留的日志文件大小以及个数,从而实现自动清除。
1348 0
21_Android中常见对话框,光传感器,通过重力感应器编写出指南针应用,帧动画,通过Jav代码的方式编写补间动画,通过XML的方式编写补间动画
 1 关于常见的对话框,主要有: 常见的对话框,单选对话框,多选对话框,进度条对话框(转圈类型的),带进度条的对话框。 案例结构: 完成如下结构的案例,将所有的案例都测试一下: 2 编写MainActivity,代码如下: package com.itheima.dialog;   import android.app.Activity; import and
1167 0
5723
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载