封装一个基于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 =
null
,
bool
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 =
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异步目标包裹器来包装一次即可。
本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/8641403.html ,如需转载请自行联系原作者