目录 前言 自定义参数 日志输出方式 文件 网络传输 数据库 科学使用 参考文档 前言 在一年前,我写过一篇关于NLog入门文章《NLog日志框架使用探究-1》,文章简单的介绍了Nlog的基本使用以及如何使用Log4View2工具配合统一收集日志查看。本篇文章会记录一些NLog常用的用法。 自定义参数 有时候我们需要根据我们的业务特征自定义一些参数。比如有个唯一的Id。这时候我们可以自定义参数,将Id提取出来,而不是放到日志内容中,这样可以方便检索。 在EventProperties Layout Renderer文档中,支持自定义EventPropertie动态的渲染到Layout中。 Nlog已经有一些自定义的参数了,如${counter}、${longdate}、${message:format=message}等。 自定义的参数使用格式为${event-properties:item=String:culture=String:format=String}。 官方示例如下,代码中定义了四种Property ... Logger logger = LogManager.GetCurrentClassLogger(); LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, "", "Pass my custom value"); theEvent.Properties["MyValue"] = "My custom string"; theEvent.Properties["MyDateTimeValue"] = new DateTime(2015, 08, 30, 11, 26, 50); theEvent.Properties["MyDateTimeValueWithCulture"] = new DateTime(2015, 08, 30, 11, 26, 50); theEvent.Properties["MyDateTimeValueWithCultureAndFormat"] = new DateTime(2015, 08, 30, 11, 26, 50); logger.Log(theEvent); ... 在配置文件中可以通过${event-properties:item=String:culture=String:format=String}获取到 ${event-properties:item=MyValue} -- renders "My custom string" ${event-properties:MyDateTimeValue:format=yyyy-M-dd}"; -- renders "2015-8-30" ${event-properties:MyDateTimeValueWithCulture:culture=en-US} -- renders "8/30/2015 11:26:50 AM" ${event-properties:MyDateTimeValueWithCultureAndFormat:format=yyyy-M-dd HH:mm:ss:culture=en-US} -- renders "2015-8-30 11:26:50" 从上可以看出,若我们需要自定义参数,我们需要创建LogEventInfo对象,并通过Log()方法记录LogEventInfo对象。 调用 Info()等方法内部实际也是创建了LogEventInfo对象,最终还是调用Log()方法。 下面我们可以自己的代码测试一下。 修改上面的Json输出的配置,由于Memo参含有中文,因此需要将encode设置为false,防止被编码为Unicode。以下为Nlog相关源码 protected override void RenderInnerAndTransform(LogEventInfo logEvent, StringBuilder builder, int orgLength) { Inner.RenderAppendBuilder(logEvent, builder); if (JsonEncode && builder.Length > orgLength) { if (RequiresJsonEncode(builder, orgLength)) { var str = builder.ToString(orgLength, builder.Length - orgLength); builder.Length = orgLength; Targets.DefaultJsonSerializer.AppendStringEscape(builder, str, EscapeUnicode); } } } private bool RequiresJsonEncode(StringBuilder target, int startPos = 0) { for (int i = startPos; i < target.Length; ++i) { if (Targets.DefaultJsonSerializer.RequiresJsonEscape(target[i], EscapeUnicode)) { return true; } } return false; } 在上一篇文章中有同学提问,当encode设置为false时,输出的内容不会有双引号。查阅了下一源码,确实如此。具体为什么这样设计不是很理解,有知道的同学可以说明一下。 public class JsonAttribute { ... public bool Encode { get => LayoutWrapper.JsonEncode; set => LayoutWrapper.JsonEncode = value; } ... } private bool RenderAppendJsonPropertyValue(JsonAttribute attrib, LogEventInfo logEvent, StringBuilder sb, bool beginJsonMessage) { BeginJsonProperty(sb, attrib.Name, beginJsonMessage); if (attrib.Encode) { // "\"{0}\":{1}\"{2}\"" sb.Append('"'); } ... if (attrib.Encode) { sb.Append('"'); } return true; } 接下来在nlog.Config的target配置中添加以下配置 代码对应的Properites LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, "", "自定义动态参数"); theEvent.Properties["Id"] = Guid.NewGuid(); theEvent.Properties["No"] = "1"; theEvent.Properties["Memo"] = "备注"; logger.Log(theEvent); 输出如下图 17.png 需要注意若我们自定义参数,使用json格式写入到文件,则代码中的Properties的Key必须和配置文件的${event-properties:item=key}中的key大小写一致。 日志输出方式 文件 当我们日志需要以文件存放时,通常情况需要根据服务名、模块名等区分日志目录,同样可以通过自定义参数输出。 假设我们需要将日志按服务分目录,同时日志文件名含有我们指定的内容前缀,在每一条日志中需要记录一个唯一的编号。日志配置如下 ... 先看下记录下来的日志,圈出来的都是我们自定义生成的值。 20191202143515.png ${basedir}是程序的运行目录 ${logger:shortName=true}是代码中指定的程序名名称,在代码中可以通过NLog.LogManager.GetLogger("test")指定日志名或NLog.LogManager.GetCurrentClassLogger()指向当前类的全名(包括命名空间)。 ${shortdate}是短日期格式,Nlog也内置了${date}获取完整的时间,前面我们说过了可以通过${event-properties:item=String:culture=String:format=String}自定义格式,这里也可以通过${date:format=String}自定义日期格式,比如${date:format=yyyyMMdd}输出的就是如20191201的日期格式。 网络传输 上一章我们提到,日志通过网络发送到Log4View2等工具统一汇总。 ... Nlog支持tcp或udp协议进行网络传输。 通过xsi:type="Network"指定网络传输 通过address="协议://ip:端口"指定协议和地址。 通过layout="${log4jxmlevent:includeCallSite=true:includeNLogData=true}序列化为XML传输,当然我们也可以传输自定义的格式或Json格式。只要在目标端使用对应的格式解析即可。 下面还是通过Xml序列化传输到Log4View2为例。当我们代码中自定义的字段序列化成Xml发送到对端。我们可以在Log4View2界面上的列右键选择Show Column Chooser项选择哪些字段显示,非常方便。 18.png 还支持筛选列,方便我们查找。 19.png 数据库 一般情况下日志也不需要实时查看,通常都是排查问题的时候需要看,因此有时候我们可以希望先将日志统一汇总后在做日志分析等工作。Nlog支持将数据插入数据库,比如我将日志入库到Oracle数据库中,使用Oracle.ManagedDataAccess。我们可以通过nuget安装库包Install-Package Oracle.ManagedDataAccess dbProvider:首先配置dbProvider。 keepConnection:表示是否需要保持连接。 optimizeBufferReuse:表示是否是否使用连接池。 connectionString:入库的语句。 connectionString:连接字符串。 commandText:sql语句,sql语句支持参数化。 :参数,name为参数名,layout为参数值。 在Log4View2可以将数据源指向日志所在的表。选择数据库接收器。 20191202195835.png 填写相关配置后,选择表。 20191202163947.png 选择表的时候需要选择一个Key,但并不是所有Key都是可选的。 从Log4View2源码看,Key需要满足是id结尾时类型是数值或时间类型或者列设置了自增。 this.IsKey = ((this.Name.ToLowerInvariant().EndsWith("id") && DbMessageKey.IsValidKeyType(this.Type)) || column.AutoIncrement); public static bool IsValidKeyType(Type type) { return type == typeof(int) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong) || type == typeof(decimal) || type == typeof(DateTime); } 1.gif 这个key是用于时间筛选的。在日志配置中也可以设置获取指定的日志等级,或者,我们可以指定一个列作为时间筛选条件。 看下Log4View2的源码,在DBReceiver初始化的时候会把我们选择的Key传入赋值给_dbMessageKey public DbReceiver(IReceiverFactory factory, ReceiverConfig recRow) : base(factory, recRow) { ... this._columns = new DbColumns(dbReceiverConfig.DbColumns); this._dbMessageKey = this._columns.Key; ... } 在初始化查询sql的时候就会用到该值 private DbCommand CreateReadQuery() { ... DbCommand dbCommand = this._database.CreateCommand(); dbCommand.CommandTimeout = this._commandTimeout; string parameterName = this._database.GetParameterName(0); string arg = this._dbMessageKey.IsUnique ? ">" : ">="; string text = this._database.QuoteName(this._dbMessageKey.Name); string tableName = this._database.QuoteName(this._tableName); DbParameter dbParameter = dbCommand.CreateParameter(); dbParameter.ParameterName = parameterName; dbParameter.DbType = this._dbMessageKey.DbType; dbParameter.Value = this._dbMessageKey.ParameterValue; dbCommand.Parameters.Add(dbParameter); string text2 = string.Format("WHERE ({0} {2} {1})", text, parameterName, arg); ... return dbCommand; } 20191202180402.png 20191202180450.png 科学使用 Log4View2工具首次安装使用有30天的试用期,试用期过了一些功能就会被限制。下一章我会讲解如何是使用反编译工具科(po)学(jie)使用Log4View2。 参考文档 Event Context Layout Renderer EventProperties Layout Renderer Log4ViewHelp DatabaseTarget.DBProvider Property Database target 20191127212134.png 微信扫一扫二维码关注订阅号杰哥技术分享 出处:本文地址:https://www.cnblogs.com/Jack-Blog/p/11972400.html 作者:杰哥很忙 本文使用「CC BY 4.0」创作共享协议。欢迎转载,请在明显位置给出出处及链接。https://www.cnblogs.com/Jack-Blog/p/11972400.html