封装一个基于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
378
379
380
381
382
383
384
385
386
387
388
389
/// <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 = "LogDB";
    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;
    private string loggerName = null;
    private bool needReConfigLogger = false;
 
    public static LogUtil GetInstance(string mongoDbCollName, string loggerCacheDependencyFilePath = null, bool needWriteLogToFile = true)
    {
        string key = string.Format("{0}_{1}", defaultMongoDbName, mongoDbCollName);
        return cacheLogUitls.GetOrAdd(key, new LogUtil(mongoDbCollName)
        {
            LoggerCacheDependencyFilePath = string.IsNullOrEmpty(loggerCacheDependencyFilePath) ? HttpContext.Current.Server.MapPath("~/Web.config") : loggerCacheDependencyFilePath,
            NeedWriteLogToFile = needWriteLogToFile,
            MongoDbName = defaultMongoDbName,
            MongoDbCollectionName = mongoDbCollName
        });
    }
 
    public LogUtil(string loggerName)
    {
        this.loggerName = loggerName;
        this.needReConfigLogger = true;
    }
 
    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 || needReConfigLogger)
        {
            lock (syncLocker)
            {
                if (_Logger == null || HttpRuntime.Cache[cacheKey_NLogConfigFlag] == null || needReConfigLogger)
                {
                    LoggingConfiguration config = LogManager.Configuration;
                    if (config == null)
                    {
                        config = new LoggingConfiguration();
                    }
 
                    #region 配置MONGODB的日志输出对象
                    if (!IsExistTarget(config, "mongoTarget" + mongoDbCollectionName)) //针对每个loggerName会有不同的MongoTarget
                    {
                        try
                        {
                            string mongoDbConnectionSet = ConfigUtil.GetAppSettingValue("MongoDbConnectionSet");
                            if (!string.IsNullOrEmpty(mongoDbConnectionSet))
                            {
                                mongoDbConnectionSet = CrtyAES.AESDecrypt(mongoDbConnectionSet);
                            }
 
                            MongoTarget mongoTarget = new MongoTarget();
                            mongoTarget.Name = "mongoTarget" + mongoDbCollectionName;
                            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(loggerName, LogLevel.Debug, mongoTargetNew);//规则应用到指定的loggerName上
                            config.LoggingRules.Add(rule1);
                        }
                        catch
                        { }
                    }
 
                    #endregion
 
                    #region 配置File的日志输出对象
 
                    if (NeedWriteLogToFile && !IsExistTarget(config, "fileTarget")) //所有的Logger通用一个FileTarget
                    {
                        try
                        {
                            FileTarget fileTarget = new FileTarget();
                            fileTarget.Name = "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); //规则适用所有logger
                            config.LoggingRules.Add(rule2);
                        }
                        catch
                        { }
                    }
 
                    #endregion
 
 
                    LogManager.Configuration = config;
 
                    _Logger = LogManager.GetLogger(loggerName);
 
                    HttpRuntime.Cache.Insert(cacheKey_NLogConfigFlag, "Nlog", new System.Web.Caching.CacheDependency(loggerCacheDependencyFilePath));
                    needReConfigLogger = false;
                }
            }
        }
 
        return _Logger;
 
    }
 
 
    private bool IsExistTarget(LoggingConfiguration config, string targetName)
    {
        targetName += (AsyncWriteLog ? "_wrapped" : "");
        return (config.FindTargetByName(targetName) != null);
    }
 
    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 = null, string other1 = null, string other2 = null, string 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 = null, string other1 = null, string other2 = null, string 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 = null, string other1 = null, string other2 = null, string 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 = null, string other1 = null, string other2 = null, string 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 = null, string other2 = null, string 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 = null, string other1 = null, string other2 = null, string 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 { get; set; }
 
        public int ThreadID { get; set; }
 
        public string Level { get; set; }
 
        public string Msg { get; set; }
 
        public string MachineName { get; set; }
 
        public LogProperties Properties { get; set; }
 
        public class LogProperties
        {
            public string Source { get; set; }
 
            public string DetailTrace { get; set; }
 
            public string UserID { get; set; }
 
            public string Other1 { get; set; }
 
            public string Other2 { get; set; }
 
            public string Other3 { get; set; }
        }
    }
 
 
}

  

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

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

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

 如下是去掉MONGO记录的普通本地日志版本:

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
/// <summary>
    /// 本地日志(NLog)工具类(内置默认日志配置,无需单独在配置文件中进行额外配置)
    /// author:zuowenjun
    /// date:2020-12-30
    /// </summary>
    public class LogUtils
    {
        private static Logger _Logger = null;
        private static bool _AsyncWriteLog = true;
        static LogUtil()
        {
            InitLogger();
        }
 
        private static void InitLogger()
        {
            LoggingConfiguration config = LogManager.Configuration;
            if (config == null)
            {
                config = new LoggingConfiguration();
            }
 
            if (!IsExistTarget(config, "fileTarget")) //所有的Logger通用一个FileTarget
            {
                try
                {
                    FileTarget fileTarget = new FileTarget();
                    fileTarget.Name = "fileTarget";
                    fileTarget.Layout = @"[${date}] <${threadid}> - ${level} - ${event-context:item=Source} - ${event-context:item=UserID}: ${message};Other:${event-context:item=Other};${newline}   ${exception:format=TOSTRING}${newline} ";
 
                    string procName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
                    fileTarget.FileName = "${basedir}/Logs/" + procName +"-${shortdate}" + ".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.Info, fileTargetNew); //规则适用所有logger
                    config.LoggingRules.Add(rule2);
                }
                catch
                { }
            }
             
            LogManager.Configuration = config;
            _Logger = LogManager.GetLogger("LocalFileLogger");
        }
 
        private static bool IsExistTarget(LoggingConfiguration config, string targetName)
        {
            targetName += (_AsyncWriteLog ? "_wrapped" : "");
            return (config.FindTargetByName(targetName) != null);
        }
 
        private static 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 static LogEventInfo BuildLogEventInfo(LogLevel level, string msg, string source, string uid, string other = null, Exception ex=null)
        {
            var eventInfo = new LogEventInfo();
            eventInfo.Level = level;
            eventInfo.Message = msg;
            eventInfo.Exception = ex;
            eventInfo.Properties["Source"] = source;
            eventInfo.Properties["Other"] = other;
            eventInfo.Properties["UserID"] = uid;
            return eventInfo;
        }
 
        public static void Info(string msg, string source, string uid, string other = null)
        {
            try
            {
                var eventInfo = BuildLogEventInfo(LogLevel.Info, msg, source, uid, other);
                _Logger.Log(eventInfo);
            }
            catch
            { }
        }
 
        public static void Warn(string msg, string source, string uid, string other = null)
        {
            try
            {
                var eventInfo = BuildLogEventInfo(LogLevel.Warn, msg, source, uid, other);
                _Logger.Log(eventInfo);
            }
            catch
            { }
        }
 
 
        public static void Error(string msg, string source, string uid, string other = null)
        {
            try
            {
                var eventInfo = BuildLogEventInfo(LogLevel.Error, msg, source, uid, other);
                _Logger.Log(eventInfo);
            }
            catch
            { }
        }
 
        public static void Error(Exception ex, string source, string uid, string other = null)
        {
            try
            {
                var eventInfo = BuildLogEventInfo(LogLevel.Error, ex.Message, source, uid, other,ex);
                _Logger.Log(eventInfo);
            }
            catch
            { }
        }
 
 
    }

  

posted @   梦在旅途  阅读(1260)  评论(1编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示