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

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

  

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

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

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

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

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

    封装一个基于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. python学习笔记(6)

    第6章 组合数据类型 组合类型的三种表达形式:集合.序列.字典 集合类型及操作 定义:集合是多个元素的无序组合 集合类型与数学中的集合概念一致 集合元素之间无序,每个元素唯一,不存在相同元素 集合元素 ...

  2. 漏测BUG LIst

    5. 接口设计问题 -  主从存在延时,当两个接口需要一个主库,一个从库的时候,可能会出问题,时时性 4. 开发的接口文档也得进行简单的测试,根据产品文档/业务测试接口(针对问题2) 3. 需要上的课 ...

  3. CommonsChunkPlugin

    CommonsChunk 插件的作用就是提取代码中的公共代码,然后将公共模块打包到一个独立的文件中,以便在其它的入口和模块中使用,原理就是把多个入口共同的依赖都给定义成一个新入口 多种打包情况: 单一 ...

  4. django+javascrpt+python实现私有云盘

    代码稍后上,先整理下私有云盘的相关功能介绍. 1.登陆界面 2.首页展示,有个人目录.部门目录以及公司目录,针对不用的目录设置不同的权限控制. 3.个人信息展示 4.账号管理.账号信息展示 5.账号添 ...

  5. 阿里云 DTS 实践

    控制台 https://dts.console.aliyun.com/#/task/basic/ 操作 填写源目标和目的数据库信息 选择需要迁移的数据库 检查通过 现在好像是免费的,计时收费也很便宜 ...

  6. swust oj 1051

    输出利用先序遍历创建的二叉树中的指定结点的孩子结点 1000(ms) 10000(kb) 2432 / 5430 利用先序递归遍历算法创建二叉树并输出该二叉树中指定结点的儿子结点.约定二叉树结点数据为 ...

  7. Html5视频播放器-VideoJS+Audio标签实现视频,音频及字幕同步播放

    一,VideoJS介绍 引用脚本,videojs很为你着想,直接cdn了,你都不需要下载这些代码放入自己的网站 <link href=”http://vjs.zencdn.net/c/video ...

  8. js 操作本地sqlite

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  9. [Swift]LeetCode220. 存在重复元素 III | Contains Duplicate III

    Given an array of integers, find out whether there are two distinct indices i and j in the array suc ...

  10. 为什么大一先要学C语言(面向过程)再学C++或JAVA(面向对象)?

    面向对象和面向过程各有千秋 一.面向过程与面向对象对比  面向过程:强调的是每一个功能的步骤,有很多很多方法组成,这些方法相互调用,完成需求. 面向对象:强调的是对象,然后由对象去调用功能. 面向过程 ...