封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil
封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,代码比较简单,主要是把MongoTarget的配置、FileTarget的配置集成到类中,同时利用缓存依赖来判断是否需要重新创建Logger类,完整代码如下:
/// <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异步目标包裹器来包装一次即可。
封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil的更多相关文章
- 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,nloglogutil
封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,代码比较简单,主要是把MongoTarget的配置.FileTarget的配置集成到类中,同时利用缓存依赖来判断是否需要重新创 ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
- C# 日志记录工具类--LogHelper.cs测试
C# 日志记录工具类:(适用于不想使用log4j等第三方的Log工具的时候,希望自己写个简单类实现)LogHelper.cs内容如下: using System; using System.Diagn ...
- 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类
快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...
- 一个基于POI的通用excel导入导出工具类的简单实现及使用方法
前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...
- 代码片段:基于 JDK 8 time包的时间工具类 TimeUtil
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “知识的工作者必须成为自己时间的首席执行官.” 前言 这次泥瓦匠带来的是一个好玩的基于 JDK ...
- LogHelper 日志记录帮助类
1.LogHelper 日志记录帮助类 using System; using System.Collections.Generic; using System.Linq; using System. ...
- 一个使用命令行编译Android项目的工具类
一个使用命令行编译Android项目的工具类 简单介绍 编译apk项目须要使用的几个工具,基本都在sdk中,它们各自是(Windows系统): 1.aapt.exe 资源打包工具 2.android. ...
- 基于AOP和ThreadLocal实现日志记录
基于AOP和ThreadLocal实现的一个日志记录的例子 主要功能实现 : 在API每次被请求时,可以在整个方法调用链路中记录一条唯一的API请求日志,可以记录请求中绝大部分关键内容.并且可以自定义 ...
随机推荐
- STS(Spring Tool Suite)下SSM(Spring+SpringMVC+Mybatis)框架搭建(二)
继完成controller配置并使用controller实现页面跳转,现连接数据库进行登录. 在SSM框架中,使用Mybatis与数据库连接,因此需要配置关于mybatis的配置. 废话少说直接开始: ...
- 201771010118 马昕璐 《面向对象程序设计(java)》第十三周学习总结
第一部分:理论知识学习部分 事件处理基础 1.事件源(event source):能够产生事件的对象都可以成为事件源.一个事件源是一个能够注册监听器并向监听器发送事件对象的对象. 2.事件监听器(ev ...
- maven的安装及配置
学习的目标 1.能够掌握Maven的安装 2.能够配置Maven仓库 3.理解Maven的依赖传递 4.能够掌握Maven工程的创建 准备工作 1.需要的资料(apache-maven-3.5.2,本 ...
- Katalon Studio之接口测试中token处理
前言 最近抽时间接触了一下Katalon Studio(后面简称KS),并且利用KS做了一些接口测试的试验,感觉还不错,不过其中接口授权中缺少通过token动态验证的方案,虽然KS支持Authoriz ...
- history.pushState()和history.replaceState()
Html5 新增history对象的两个方法:history.pushState()和history.replaceState(),方法执行后,浏览器地址栏会变成你传的url,而页面并不会重新载入或跳 ...
- 实战深度学习(上)OpenCV库
在如今人工智能的浪潮下,无数模拟机器学习和深度学习的开发者工具倍出,其中在计算机图形学和计算机视觉里面最流行的一个库就是OpenCV库了.计算机图形学和计算机视觉学在我们的自动驾驶和仿生机器人当中有着 ...
- 使用MUI的日期控件引起的探索——HTML5 input类型date属性
我写移动端的页面会用到MUI这个框架,个人觉得挺好用的,有很多实用的UI组件.当然坑还是有的,http://dev.dcloud.net.cn/mui/ui/ MUI官网,有兴趣的小伙伴可以看看 虽然 ...
- [Swift]LeetCode234. 回文链表 | Palindrome Linked List
Given a singly linked list, determine if it is a palindrome. Example 1: Input: 1->2 Output: false ...
- [Swift]LeetCode357. 计算各个位数不同的数字个数 | Count Numbers with Unique Digits
Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n. Examp ...
- 【Spark篇】---SparkStreaming算子操作transform和updateStateByKey
一.前述 今天分享一篇SparkStreaming常用的算子transform和updateStateByKey. 可以通过transform算子,对Dstream做RDD到RDD的任意操作.其实就是 ...