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

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

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

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

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

封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,nloglogutil的更多相关文章

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

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

  2. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  3. C# 日志记录工具类--LogHelper.cs测试

    C# 日志记录工具类:(适用于不想使用log4j等第三方的Log工具的时候,希望自己写个简单类实现)LogHelper.cs内容如下: using System; using System.Diagn ...

  4. 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类

    快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...

  5. 一个基于POI的通用excel导入导出工具类的简单实现及使用方法

    前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...

  6. 代码片段:基于 JDK 8 time包的时间工具类 TimeUtil

    摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “知识的工作者必须成为自己时间的首席执行官.” 前言 这次泥瓦匠带来的是一个好玩的基于 JDK ...

  7. LogHelper 日志记录帮助类

    1.LogHelper 日志记录帮助类 using System; using System.Collections.Generic; using System.Linq; using System. ...

  8. 一个使用命令行编译Android项目的工具类

    一个使用命令行编译Android项目的工具类 简单介绍 编译apk项目须要使用的几个工具,基本都在sdk中,它们各自是(Windows系统): 1.aapt.exe 资源打包工具 2.android. ...

  9. 基于AOP和ThreadLocal实现日志记录

    基于AOP和ThreadLocal实现的一个日志记录的例子 主要功能实现 : 在API每次被请求时,可以在整个方法调用链路中记录一条唯一的API请求日志,可以记录请求中绝大部分关键内容.并且可以自定义 ...

随机推荐

  1. 校园电商项目3(基于SSM)——配置Maven

    步骤一:添加必要文件夹 先在src/main/resources下添加两个文件夹 接着在webapp文件夹下添加一个resources文件夹存放我们的静态网页内容 WEB-INF里的文件是不会被客户端 ...

  2. nginx反向代理proxy_pass的问题

    起因:今天企业部署一个项目,用的nginx做的反向代理,配置如下: 测试结果令人失望,IP:端口 能访问项目,域名:端口 也能访问 ,但是 域名/接口名 访问失败 ################## ...

  3. delphi中 dataset容易出错的地方

    最近写delphi项目,用到的数据集中的dataset,一直修改exception啊,写下过程. 在对数据集进行任何操作之前,首先要打开数据集.要打开数据集,可以把Active属性设为True,例如: ...

  4. SECCON 2014 CTF:Shuffle

    很简单的一道小题 dia看一下是ELF文件 运行之: St0CFC}4cNOeE1WOS !eoCE{ CC T2hNto 是一串乱七八糟的字符 ida看一下: 很简单的逻辑 v5和v6是随机生成的两 ...

  5. 使用layui 做后台管理界面,在Tab中的链接点击后添加一个新TAB的解决方法

    给链接或按钮  添加 onclick="self.parent.addTab('百度','http://www.baidu.com','icon-add')" 如: <a h ...

  6. Spring4 MVC Hibernate4 maven集成

    http://www.cnblogs.com/leiOOlei/p/3727859.html

  7. [代码]--给任意网站添加聊天功能,随时聊(fa)天(che)

    感谢“topurl.cn”制作此功能并分享. 这是一段代码,在打开的网页中使用,可以加载一个外挂形式的聊天室功能, 就可以和同样访问此网站进行相同操作的网友进行聊(fa)天(che)了. 使用方法: ...

  8. fpm 打包教程

    常用yum命令: Yum安装时需要安装到指定的文件夹,则需要 --installroot yum install --installroot=/usr/src/ vim 常用rpm命令: 常用yum仓 ...

  9. 洛谷P1916 小书童——蚂蚁大战

    题目背景 小A在你的帮助下,开始“刷题”,他在小书童里发现了一款叫“蚂蚁大战”(又称蛋糕保卫战)的游戏.(你懂得) 题目描述 游戏中会出现n只蚂蚁,分别有a1,a2……an的血量,它们要吃你的蛋糕.当 ...

  10. 吉哥系列故事――恨7不成妻 HDU - 4507 数位dp

    思路  和普通的DP不一样的是 这里求的是满足条件的数的平方的和 而数位DP只跟数每位是什么密切相关  所以要开一个结构 (多加一个 数的和sum 和平方和qsum)存一下各个状态的和的情况 dp[p ...