NLog组件
程序员文章站
2022-07-09 12:55:23
在.NET Core框架中使用NLog组件记录日志,写数据库,写文件!!! ......
接触.net项目的同志们都清楚,最初在项目中记录日志常用的是log4net日志组件,随着.net框架的不对优化升级,最近新流行的日志框架nlog,下面我就对nlog组件说说自己的认知:
下载
通过nuget安装nlog
配置
在项目根目录下新建一个nlog.config(在nuget包中也可以下载nlog.config包,下载默认的位置是c盘,可能和你的工程不在同一个文件夹,不建议使用),基本目录结构:targets下面配置日志输出目标及相关参数,rules下面配置目标输出规则:
1 <?xml version="1.0" ?> 2 <nlog> 3 <targets> 4 <target></target> 5 <target></target> 6 </targets> 7 <rules> 8 <logger></logger> 9 <logger></logger> 10 </rules> 11 </nlog>
记得在nlog.config的属性中设置 copy to output directory: copy always,作用是每次重新生成解决方案的时候都会将改配置文件复制的本地目录,否则本地找不到配置文件无法将日志记录到文件中:
完整的配置文件如下,日志配置文件尽量单独创建一个文件:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <nlog xmlns="http://www.nlog-project.org/schemas/nlog.xsd" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"> 3 <targets> 4 <!--写入文件--> 5 <target xsi:type="file" name="debugfile" filename="logs\debug\${shortdate}.log" 6 layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" > 7 </target> 8 <target xsi:type="file" name="infofile" filename="logs\info\${shortdate}.log" 9 layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" > 10 </target> 11 <target xsi:type="file" name="errorfile" filename="logs\error\${shortdate}.log" 12 layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" > 13 </target> 14 15 <target xsi:type="database" name="newdatabase" > 16 <dbprovider>system.data.sqlclient</dbprovider> 17 <connectionstring> 18 data source=127.0.0.1;initial catalog=flightanalysis;persist security info=true;user id=sa;password=111111; 19 </connectionstring> 20 <commandtext> 21 insert into operatorlog(id,appname,modulename,procname,operationtype,logger,logmessage,ip,username,loglevel) 22 <!--values(@id,'','','',0,'','','','','',getdate())--> 23 values(@id,@appname,@modulename,@procname,@operationtype,@logger,@logmessage,@ip,@username,@loglevel) 24 </commandtext> 25 <parameter name="@id" layout="${event-context:item=id}" /> 26 <parameter name="@appname" layout="${event-context:item=appname}" /> 27 <parameter name="@modulename" layout="${event-context:item=modulename}" /> 28 <parameter name="@procname" layout="${event-context:item=procname}" /> 29 <parameter name="@operationtype" layout="${event-context:item=operationtype}" /> 30 <parameter name="@logger" layout="${event-context:item=logger}" /> 31 <parameter name="@logmessage" layout="${event-context:item=logmessage}" /> 32 <parameter name="@ip" layout="${event-context:item=ip}" /> 33 <parameter name="@longdate" layout="${event-context:item=longdate}" /> 34 <parameter name="@username" layout="${event-context:item=username}" /> 35 <parameter name="@createdate" layout="${longdate}" /> 36 <parameter name="@loglevel" layout="${level}" /> 37 </target> 38 </targets> 39 40 <rules> 41 <!--根据日志级别分别写文件,也可以放一个文件中--> 42 <!--<logger name="dblogger" levels="debug,info,error" writeto="myfile" />--> 43 <logger name="mylogger" level="debug" writeto="debugfile" /> 44 <logger name="mylogger" level="info" writeto="infofile" /> 45 <logger name="mylogger" level="error" writeto="errorfile" /> 46 <!--写数据库--> 47 <logger name="mylogger" levels="trace,debug,info,error" writeto="newdatabase"/> 48 </rules> 49 </nlog>
- 如在根节点(nlog)配置 internalloglevel, internallogfile,可以查看nlog输出日志时的内部信息,比如你配置文件有错误,很有帮助,不过项目发布后还是关闭比较好,以免影响效率;
- 在target外面罩了一个 <target>并且xsi:type为 asyncwrapper,即表示这条 target 将异步输出,这里我将文件和数据库日志异步输出;
- db target内指定了数据库连接字符串 connectionstring,sql语句,sql参数,还可以指定数据库/表创建和删除的脚本(推荐看nlog源码示例,这里不介绍),同时我们自定义了2个参数 action和amount;
- target参数里有些是nlog内置参数,比如message,level,date,longdate,exception,stacktrace等,nlog在输出时会自动赋值;
- layout设置了每条日志的格式;
- 在rules节点,我们分别指定了三个target输出日志的级别,nlog 用于输出日志的级别包括:trace,debug,info,warn,error,fatal,可以设置 minlevel设置最小级别,也可以用 levels定义你所有需要的级别(多个用逗号分隔)。
- event-context代表自定义的参数。
路由规则(rules)
<rules />区域定义了日志的路由规则。每一个路由表项就是一个<logger />元素。<logger />有以下属性:
- name - 日志源/记录者的名字 (允许使用通配符*)
- minlevel - 该规则所匹配日志范围的最低级别
- maxlevel - 该规则所匹配日志范围的*别
- level - 该规则所匹配的单一日志级别
- levels - 该规则所匹配的一系列日志级别,由逗号分隔。
- writeto - 规则匹配时日志应该被写入的一系列目标,由逗号分隔。
- final - 标记当前规则为最后一个规则。其后的规则即时匹配也不会被运行
封装
对nlog.config的logger进行简单封装:
1 /// <summary> 2 /// 日志类,只提供接口 3 /// 2018-11-6 15:32:01 4 /// </summary> 5 public class logger 6 { 7 #region 初始化 8 //获取指定的名称为logger。 9 //private static nlog.logger _dblogger = nlog.logmanager.getlogger("mylogger"); 10 /// <summary> 11 /// 日事件间类 12 /// </summary> 13 private logeventinfo lei = new logeventinfo(); 14 /// <summary> 15 /// 数据错误无法获取用户时使用 16 /// </summary> 17 public static string defaultuser = "system"; 18 /// <summary> 19 /// 默认ip地址 20 /// </summary> 21 public static string defaultip = "127.0.0.1"; 22 /// <summary> 23 /// 提供日志接口和实用程序功能 24 /// </summary> 25 private nlog.logger _logger = null; 26 /// <summary> 27 /// 自定义日志对象供外部使用 28 /// </summary> 29 public static logger default { get; private set; } 30 31 private logger(nlog.logger logger) 32 { 33 _logger = logger; 34 } 35 public logger(string name) : this(logmanager.getlogger(name)) 36 { } 37 38 static logger() 39 { 40 //获取具有当前类名称的日志程序。 41 default = new logger("mylogger"); 42 } 43 #endregion 44 45 #region debug 46 public void debug(string msg, params object[] args) 47 { 48 _logger.debug(msg, args); 49 } 50 51 public void debug(string msg, exception err) 52 { 53 _logger.debug(err, msg); 54 } 55 #endregion 56 57 #region info 58 public void info(string msg, params object[] args) 59 { 60 _logger.info(msg, args); 61 } 62 63 public void info(string msg, exception err) 64 { 65 _logger.info(err, msg); 66 } 67 #endregion 68 69 #region warn 70 /// <summary> 71 ///警告 72 /// </summary> 73 /// <param name="msg">警告信息</param> 74 /// <param name="args">动态参数</param> 75 public void warn(string msg, params object[] args) 76 { 77 _logger.warn(msg, args); 78 } 79 /// <summary> 80 ///警告 81 /// </summary> 82 /// <param name="msg">警告信息</param> 83 /// <param name="err">异常信息</param> 84 public void warn(string msg, exception err) 85 { 86 _logger.warn(err, msg); 87 } 88 #endregion 89 90 #region trace 91 /// <summary> 92 /// 使用指定的参数在跟踪级别写入诊断消息 93 /// </summary> 94 /// <param name="msg">跟踪信息</param> 95 /// <param name="args">动态参数</param> 96 public void trace(string msg, params object[] args) 97 { 98 _logger.trace(msg, args); 99 } 100 /// <summary> 101 /// 使用指定的参数在跟踪级别写入诊断消息 102 /// </summary> 103 /// <param name="msg">跟踪信息</param> 104 /// <param name="args">异常信息</param> 105 public void trace(string msg, exception err) 106 { 107 _logger.trace(err, msg); 108 } 109 #endregion 110 111 #region error 112 /// <summary> 113 /// 使用指定的参数在错误级别写入诊断消息。 114 /// </summary> 115 /// <param name="msg">错误信息</param> 116 /// <param name="args">动态参数</param> 117 public void error(string msg, params object[] args) 118 { 119 _logger.error(msg, args); 120 } 121 /// <summary> 122 /// 使用指定的参数在错误级别写入诊断消息。 123 /// </summary> 124 /// <param name="msg">错误信息</param> 125 /// <param name="args">异常信息</param> 126 public void error(string msg, exception err) 127 { 128 _logger.error(err, msg); 129 } 130 #endregion 131 132 #region fatal 133 /// <summary> 134 /// 使用指定的参数在致命级别写入诊断消息。 135 /// </summary> 136 /// <param name="msg">致命错误</param> 137 /// <param name="args">动态参数</param> 138 public void fatal(string msg, params object[] args) 139 { 140 _logger.fatal(msg, args); 141 } 142 /// <summary> 143 /// 使用指定的参数在致命级别写入诊断消息。 144 /// </summary> 145 /// <param name="msg">致命错误</param> 146 /// <param name="args">异常信息</param> 147 public void fatal(string msg, exception err) 148 { 149 _logger.fatal(err, msg); 150 } 151 /// <summary> 152 /// 刷新所有挂起的日志消息(在异步目标的情况下)。 153 /// </summary> 154 /// <param name="timeoutmilliseconds">最大的时间允许冲洗。此后的任何消息都将被丢弃。</param> 155 public void flush(int? timeoutmilliseconds = null) 156 { 157 if (timeoutmilliseconds != null) 158 nlog.logmanager.flush(timeoutmilliseconds.value); 159 160 nlog.logmanager.flush(); 161 } 162 #endregion 163 164 165 #region operator日志写入 166 /// <summary> 167 /// 写入日志信息 168 /// </summary> 169 /// <param name="operatorlogmodel">操作信息</param> 170 public void insoperatorlog(operatorlogmodel operatorlogmodel) 171 { 172 var level = loglevel.info; 173 if (operatorlogmodel.loglevel == nlog.loglevel.trace) 174 level = loglevel.trace; 175 else if (operatorlogmodel.loglevel == nlog.loglevel.debug) 176 level = loglevel.debug; 177 else if (operatorlogmodel.loglevel == nlog.loglevel.info) 178 level = loglevel.info; 179 else if (operatorlogmodel.loglevel == nlog.loglevel.warn) 180 level = loglevel.warn; 181 else if (operatorlogmodel.loglevel == nlog.loglevel.error) 182 level = loglevel.error; 183 else if (operatorlogmodel.loglevel == nlog.loglevel.fatal) 184 level = loglevel.fatal; 185 186 if (operatorlogmodel.logmessage.length > 3000) 187 { 188 operatorlogmodel.logmessage = operatorlogmodel.logmessage.substring(0, 3000); 189 } 190 lei.properties["id"] = guid.newguid().tostring("d"); 191 lei.properties["appname"] = operatorlogmodel.appname; 192 lei.properties["modulename"] = operatorlogmodel.modulename; 193 lei.properties["procname"] = operatorlogmodel.procname; 194 lei.properties["operationtype"] = operatorlogmodel.operationtype; 195 lei.properties["logger"] = operatorlogmodel.logger; 196 lei.properties["logmessage"] = operatorlogmodel.logmessage; 197 lei.properties["ip"] = operatorlogmodel.ip ?? defaultip; 198 lei.properties["longdate"] = operatorlogmodel.longdate; 199 lei.properties["username"] = operatorlogmodel.username ?? defaultuser; 200 lei.properties["createdate"] = operatorlogmodel.createdate; 201 lei.level = operatorlogmodel.loglevel; 202 _logger.log(level, lei); 203 } 204 #endregion 205 }
对操作类型进行简单封装,也可以自定义:
1 /// <summary> 2 /// 操作类型枚举 3 /// </summary> 4 public enum operationtype 5 { 6 /// <summary> 7 /// 保存或添加 8 /// </summary> 9 [system.componentmodel.description("添加")] 10 add, 11 /// <summary> 12 /// 更新 13 /// </summary> 14 [system.componentmodel.description("更新")] 15 update, 16 /// <summary> 17 /// 核销 18 /// </summary> 19 [system.componentmodel.description("核销")] 20 audit, 21 /// <summary> 22 /// 查看 23 /// </summary> 24 [system.componentmodel.description("指派")] 25 assign, 26 /// <summary> 27 /// 删除 28 /// </summary> 29 [system.componentmodel.description("删除")] 30 delete, 31 /// <summary> 32 /// 读取/查询 33 /// </summary> 34 [system.componentmodel.description("查询")] 35 retrieve, 36 /// <summary> 37 /// 登录 38 /// </summary> 39 [system.componentmodel.description("登录")] 40 login, 41 /// <summary> 42 /// 查看 43 /// </summary> 44 [system.componentmodel.description("查看")] 45 look 46 }
自定义类,主要用于绑定数据:
1 /// <summary> 2 /// 操作日志类 3 /// </summary> 4 public class operatorlogmodel 5 { 6 /// <summary> 7 /// 自增主键id 8 /// </summary> 9 public string id { get; set; } 10 /// <summary> 11 /// 一级菜单 12 /// </summary> 13 public string appname { get; set; } 14 /// <summary> 15 /// 二级菜单 16 /// </summary> 17 public string modulename { get; set; } 18 /// <summary> 19 /// 本级菜单 20 /// </summary> 21 public string procname { get; set; } 22 /// <summary> 23 /// 操作类型 24 /// </summary> 25 public int operationtype { get; set; } 26 /// <summary> 27 /// 日志文件 28 /// </summary> 29 public string logger { get; set; } 30 /// <summary> 31 /// 日志信息 32 /// </summary> 33 public string logmessage { get; set; } 34 /// <summary> 35 /// ip地址 36 /// </summary> 37 public string ip { get; set; } 38 /// <summary> 39 /// 记录时间 40 /// </summary> 41 public string longdate { get; set; } 42 /// <summary> 43 /// 用户名称 44 /// </summary> 45 public string username { get; set; } 46 /// <summary> 47 /// 日志级别 48 /// </summary> 49 public nlog.loglevel loglevel { get; set; } 50 /// <summary> 51 /// 创建时间 52 /// </summary> 53 public datetime createdate { get; set; } 54 }
创建数据库表,字段可以自定义,此处用的是sql server:
1 create table [dbo].[operatorlog]( 2 [id] [varchar](60) not null, 3 [appname] [varchar](20) not null, 4 [modulename] [varchar](30) not null, 5 [procname] [varchar](30) not null, 6 [operationtype] [int] not null, 7 [logger] [varchar](500) not null, 8 [logmessage] [varchar](3000) not null, 9 [ip] [varchar](32) not null, 10 [username] [varchar](36) not null, 11 [createdate] [datetime] not null, 12 [loglevel] [varchar](12) not null, 13 constraint [pk_operatorlog] primary key clustered 14 ( 15 [id] asc 16 )with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary] 17 ) on [primary] 18 19 go 20 21 set ansi_padding off 22 go 23 24 alter table [dbo].[operatorlog] add constraint [df_operatorlog_id] default ('') for [id] 25 go 26 27 alter table [dbo].[operatorlog] add constraint [df_operatorlog_appname] default ('') for [appname] 28 go 29 30 alter table [dbo].[operatorlog] add constraint [df_operatorlog_modulename] default ('') for [modulename] 31 go 32 33 alter table [dbo].[operatorlog] add constraint [df_operatorlog_procname] default ('') for [procname] 34 go 35 36 alter table [dbo].[operatorlog] add constraint [df_operatorlog_operationtype] default ((0)) for [operationtype] 37 go 38 39 alter table [dbo].[operatorlog] add constraint [df_operatorlog_logger] default ('') for [logger] 40 go 41 42 alter table [dbo].[operatorlog] add constraint [df_operatorlog_logmessage] default ('') for [logmessage] 43 go 44 45 alter table [dbo].[operatorlog] add constraint [df_operatorlog_ip] default ('') for [ip] 46 go 47 48 alter table [dbo].[operatorlog] add constraint [df_operatorlog_username] default ('') for [username] 49 go 50 51 alter table [dbo].[operatorlog] add constraint [df__operatorl__creat__02084fda] default (getdate()) for [createdate] 52 go 53 54 alter table [dbo].[operatorlog] add constraint [df_operatorlog_loglevel] default ('') for [loglevel] 55 go 56 57 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'日志表主键id' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'id' 58 go 59 60 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'一级菜单' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'appname' 61 go 62 63 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'二级菜单' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'modulename' 64 go 65 66 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'本级菜单' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'procname' 67 go 68 69 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'操作类型' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'operationtype' 70 go 71 72 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'日志文件' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'logger' 73 go 74 75 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'日志内容' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'logmessage' 76 go 77 78 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'ip地址' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'ip' 79 go 80 81 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'用户名' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'username' 82 go 83 84 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'创建时间' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'createdate' 85 go 86 87 exec sys.sp_addextendedproperty @name=n'ms_description', @value=n'日志级别' , @level0type=n'schema',@level0name=n'dbo', @level1type=n'table',@level1name=n'operatorlog', @level2type=n'column',@level2name=n'loglevel' 88 go
引用日志如下:
1 public class program 2 { 3 public static void main(string[] args) 4 { 5 operatorlogmodel opmodel = new operatorlogmodel(); 6 opmodel.appname = "系统管理"; 7 opmodel.modulename = "权限管理"; 8 opmodel.procname = "用户管理"; 9 opmodel.operationtype = convert.toint32(enum.parse(typeof(operationtype), operationtype.retrieve.tostring())); 10 opmodel.username = "ss"; 11 //opmodel.loglevel = nlog.loglevel.trace; 12 opmodel.longdate = datetime.now.tostring(); 13 opmodel.createdate = datetime.now; 14 opmodel.logger = "dfdfd"; 15 opmodel.logmessage = "测试测试测试!!!"; 16 logger.default.error("dsfsfsfd"); 17 //string ip = request.httpcontext.connection.remoteipaddress.tostring(); 18 19 //logger.default.info("就是这么霸气"); 20 21 logger.default.insoperatorlog(opmodel); 22 createwebhostbuilder(args).build().run(); 23 } 24 25 public static iwebhostbuilder createwebhostbuilder(string[] args) => 26 webhost.createdefaultbuilder(args) 27 .usestartup<startup>(); 28 }
数据库插入的操作日志结果如下:
文件中记录的日志如下:
以上就是nlog日志组件的简单封装,欢迎纠错!!!
上一篇: mysql利用binlog进行数据恢复
下一篇: 成年人的世界:约会也要加个班