在 Web API开发中,日志组件是非常重要的一部分,它可以帮助开发者跟踪和记录 API 的运行过程,以便进行故障排除、性能优化和安全审计。
log4net 是 Apache 基金会的一个日志框架,提供了灵活的日志记录和过滤功能,可以方便地集成到 .NET Web API中。
log4net 是第三方的日志组件,首先需要在包管理器中安装 log4net 包。
可以给整个解决方案安装 log4net 包,右键 “解决方案——管理解决方案的NuGet程序包(N)”,在 “浏览” 中搜索 log4net,然后点击安装。
因为 log4net 是第三方的日志组件,所以要集成到 ASP.NET Core 中,还需要安装一个包:Microsoft.Extensions.Logging.Log4Net.AspNetCore
这个包在搜索 log4net 的时候默认显示在第二行,如果没显示,就单独搜索。
因为是给整个解决方案安装,所以项目和类库中都被安装了。
接下来为了使 log4net 生效,需要创建配置文件进行配置。
在项目中创建 LogConfig 文件夹,然后在文件夹内创建 log4net.Config 的配置文件。
在 log4net.Config 配置文件中写入内容:
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!--日志写入文件的配置-->
<appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
<!--设置日志记录时的路径和名称-->
<file value="log4net\log.txt" />
<!--置为 true,当前最新日志文件名永远为上面 file 中设置的名字-->
<staticLogFileName value="true" />
<!--是否允许追加日志内容-->
<appendToFile value="true" />
<!--当备份文件时,为文件名加的后缀-->
<!--每一个日志文件都会增加一个年月日的后缀-->
<dataPattern value="yyyyMMdd.txt" />
<!--最小锁定模型以允许多个进程可以写入同一个文件,防止多线程时不能写log,官方说线程非安全-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<!--设置日志的组合方式-->
<!--可以为:Once|Size[大小]|Date[日期]|Composite-->
<!--其中Composite为Size和Date的组合-->
<rollingStyle value="Composite" />
<!--日志最大个数,都是最新的-->
<!--rollingStyle节点为Size时,只能有value个日志-->
<!--rollingStyle节点为Composite时,每天有value个日志-->
<maxSizeRollBackups value="20" />
<!--可用的单位:KB|MB|GB-->
<maximumFileSize value="3MB" />
<!--输出级别在INFO和ERROR之间的日志-->
<filter type="log4net.Filter.levelRangeFilter">
<!--记录日志级别ALL到日志级别FATAL的日志-->
<!--日志级别见下方root标签中的设置-->
<param name="LevelMin" value="ALL" />
<param name="LevelMax" value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<!--日志保存的结果:时间、线程id、级别、logger、具体的日志消息-->
<!--这是日志文件中保存的日志,与下方的设置一一对应:2024-06-03 23:35:35,654 [18] ERROR webapi_rumen.Controllers.SecondController - LogError:this is second 构造函数-->
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<!--控制级别:由低到高:ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
<!--ALL:DEBUG,INFO,WARN,ERROR,FATAL-->
<!--DEBUG:INFO,WARN,ERROR,FATAL-->
<!--INFO:INFO,WARN,ERROR,FATAL-->
<!--WARN:WARN,ERROR,FATAL-->
<!--ERROR:ERROR,FATAL-->
<!--FATAL:FATAL-->
<!--OFF:0-->
<priority value="ALL" />
<level value="INFO" />
<!--指定要使用的日志配置(日志名称保存在上方appender标签中)-->
<appender-ref ref="rollingAppender" />
<appender-ref ref="AdoNetAppender_SqlServer" />
</root>
</log4net>
然后右键 log4netFile.Config 配置文件——属性,设置 “复制到输出目录” 的值为 “始终复制”。
这样在启动项目或重新生成项目后,在执行目录的下就能生成日志配置文件了,下面是重新生成项目前后的对比。
重新生成项目前
重新生成项目后
至此 log4net 的配置文件设置完成。
继续设置配置文件的读取,让配置文件生效。
在 Program.cs 中配置 log4net:builder.Logging.AddLog4Net("LogConfig/log4net.config");
接下来需要写日志,创建一个控制器 SecondController,并写入内容。
在 SecondController 中写入日志的方法有 2 个,都能成功写入日志。
启动项目之前 bin\Debug\net6.0 路径中没有 log4 文件夹
启动项目之后, bin\Debug\net6.0 路径中有了 log4 文件夹,并且里面有 log.txt 文件。
在 swagger 中调用 SecondController 中的 Index() 方法后,log.txt 中被写入日志内容。
先在项目上 “右键——管理 NuGet 程序包”,在浏览中搜索:system.data.sqlclient,并安装。
在 SqlServer 数据库中创建 t_log4net 表,设置 id 为自增。
在 log4net 的配置文件中,增加对 SqlServer 数据库的配置。
其中执行语句 <commandText value="INSERT INTO Log4Net ([log_date],[Thread],[log_level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/> 里插入的字段,要与数据库中表的字段一致。
<!--日志写入数据库的配置-->
<!--SqlServer 数据库配置-->
<appender name="AdoNetAppender_SqlServer" type="log4net.Appender.ADONetAppender">
<!--日志缓存写入条数:设置为0时,只要有一条就立即写到数据库-->
<bufferSize value="0"/>
<!-- 连接 SqlServer 数据库配置 -->
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data.SqlClient, Version=4.6.1.3, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<connectionString value="server=192.168.1.2;database=test;user id=sa;password=123456"/>
<!-- 插入日志的配置 -->
<commandText value="INSERT INTO Log4Net ([log_date],[Thread],[log_level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
<parameter>
<parameterName value="@log_date"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout"/>
</parameter>
<parameter>
<parameterName value="@thread"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread"/>
</layout>
</parameter>
<parameter>
<parameterName value="@log_level"/>
<dbType value="String"/>
<size value="50"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level"/>
</layout>
</parameter>
<parameter>
<parameterName value="@logger"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger"/>
</layout>
</parameter>
<parameter>
<parameterName value="@message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
</layout>
</parameter>
<parameter>
<parameterName value="@exception"/>
<dbType value="String"/>
<size value="2000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
</appender>
配置完成后,在配置文件的 root 标签中指定需要使用的数据库配置:<appender-ref ref="AdoNetAppender_SqlServer" />
重新启动项目,启动成功后调用 SecondController 里面的 index() 方法。
查看日志文件,日志写入成功。
查看数据库日志表,日志写入成功。
先在项目上 “右键——管理 NuGet 程序包”,在浏览中搜索:MySql.Data,并安装。
在 MySQL 数据库中创建 t_log4net 表,设置 id 为自增。
create table t_log4net(
id int primary key auto_increment comment 'id',
log_date datetime comment '日志时间',
thread varchar(255) comment '线程',
log_level varchar(55) comment '日志等级',
logger varchar(255) comment '触发日志的对象',
message varchar(4000) comment '日志信息',
exception varchar(2000) comment '异常信息'
) comment = 'log4net 日志表';
在 log4net 的配置文件中,增加对 MySQL 数据库的配置。
其中执行语句 <commandText value="INSERT INTO t_log4net (log_date,thread,log_level,logger,message,exception) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/> 里插入的字段,要与数据库中表的字段一致。
<!--MySQL 数据库配置-->
<appender name="AdoNetAppender_MySQL" type="log4net.Appender.ADONetAppender">
<!--日志缓存写入条数:设置为0时,只要有一条就立即写到数据库-->
<bufferSize value="0"/>
<!-- 连接 MySQL 数据库配置 -->
<connectionType value="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" />
<connectionString value="server=192.168.1.2;userid=root;pwd=123456;port=3306;database=test;SslMode=none" />
<!-- 插入日志的配置 -->
<commandText value="INSERT INTO t_log4net (log_date,thread,log_level,logger,message,exception) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
<parameter>
<parameterName value="@log_date"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout"/>
</parameter>
<parameter>
<parameterName value="@thread"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread"/>
</layout>
</parameter>
<parameter>
<parameterName value="@log_level"/>
<dbType value="String"/>
<size value="50"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level"/>
</layout>
</parameter>
<parameter>
<parameterName value="@logger"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger"/>
</layout>
</parameter>
<parameter>
<parameterName value="@message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
</layout>
</parameter>
<parameter>
<parameterName value="@exception"/>
<dbType value="String"/>
<size value="2000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
</appender>
配置完成后,在配置文件的 root 标签中指定需要使用的数据库配置:<appender-ref ref="AdoNetAppender_MySQL" />
重新启动项目,启动成功后调用 SecondController 里面的 index() 方法。
查看数据库日志表,日志写入成功。
NLog 是另一个流行的日志库,具有灵活的配置选项和丰富的目标输出,支持文件、数据库、网络等多种日志存储方式。
在项目上 “右键——管理 NuGet 程序包”,引入 Nlog.Web.AspNetCore 程序集。
设置配置文件,在 LogConfig 文件夹中新建 NLog.Config 文件。
写入 Nlog.Config 文件的配置内容
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwException="false"
internalLogLevel="off" internalLogFile="c:\temp\nlog-interna.log">
<variable name="myvar" value="myvalue" />
<targets>
<target xsi:type="File" name="allFile" fileName="NLog\nlog-all-${shortdate}.log"
layout="${longdate} | ${logger} | ${uppercase:${level}} | ${message} ${exception}" />
<!-- 与上面写入到文件的 target 相比
1、同样是将文件写入日志中,写入的内容有所差别,差别在 layout 属性中体现;
2、写入日志的数量有差别,差别在下面的路由逻辑中体现(路由的匹配规则是由上往下)
-->
<target xsi:type="File" name="ownFile-web" fileName="NLog\nlog-my-${shortdate}.log"
layout="${longdate} | ${logger} | ${uppercase:${level}} | ${message} ${exception}" />
<targt xsi:type="Null" name="blackhole" />
</targets>
<!-- 日志的路由规则配置:在上面的配置中从上往下匹配 -->
<!-- 如果匹配到了含 final 属性的路由,就不会继续往下匹配了 -->
<rules>
<!-- * 代表所有日志,包括 Microsoft.*-->
<logger name="*" minlevel="Trace" writeTo="allFile" />
<!-- 以 Microsoft 打头的日志将进入此路由,由于此路由没有 writeTo 属性,所以会被忽略 -->
<!-- 且此路由设置了 final,所以当此路由被匹配到时,不会再匹配此路由下面的路由,未匹配到时才会继续匹配下一个路由 -->
<logger name="Microsoft.*" minlevel="Trace" final="true" />
<!-- 上方已经过滤了所有 Microsoft.* 的日志,所以此处的日志只会打印除 Microsoft.* 以外的日志 -->
<logger name="*" minLevel="Trace" writeTo="ownFile-web" />
</rules>
</nlog>
在 Program.cs 中引用 NLog(把 log4net 的引入注释掉)
// 配置 Nlog,指定配置文件
builder.Logging.AddNLog("LogConfig/NLog.config");
启动项目后,成功生成 NLog 文件夹。
可以看到在 NLog 文件夹中生成了一个 nlog-all-2024-06-06.log 文件。
里面已经写入了很多系统日志
在 Swagger 里面调用 SecondController 里的 index() 方法
可以看到在 NLog 文件夹下,又生成了一个 nlog-my-2024-06-06.log 文件,内容中没有系统日志,只有用户输出的日志。
这个时候再看下 nlog-all-2024-06-06.log 文件中的内容,发现除了系统日志外,里面也有用户输出的日志。
综上所述:
nlog-all-2024-06-06.log 中记载了所有日志,既有系统的,也有用户输出的。
nlog-my-2024-06-06.log 中只记载用户输出的日志。
这正对应着配置文件中的配置,这两个配置可根据需要进行使用,不需要的可以注释掉。
先在项目上 “右键——管理 NuGet 程序包”,在浏览中搜索:system.data.sqlclient,并安装。
在 SqlServer 数据库中创建 t_nlog 表,设置 id 为自增。
在 Nlog 的配置文件中,增加对 SqlServer 数据库的配置。
<!-- 将日志写入 SqlServer 数据库 -->
<!-- 数据库中表的字段,需要与下面配置中的一致 -->
<target xsi:type="Database" name="DbSqlServer"
dbProvider="System.Data.SqlClient.SqlConnection,System.Data.SqlClient"
connectionString="server=192.168.1.2;database=test;user id=sa;password=123456"
commandText="insert into t_nlog(application,logged,log_level,message,logger,call_site,exception) values(@application,@logged,@logLevel,@message,@logger,@callSite,@exception)">
<parameter name="@application" layout="AspNetCoreNlog" />
<parameter name="@logged" layout="${date}" />
<parameter name="@logLevel" layout="${level}" />
<parameter name="@message" layout="${message}" />
<parameter name="@logger" layout="${logger}" />
<parameter name="@callSite" layout="${callsite:filename=true}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
配置完成后,在配置文件的 rules 标签中指定需要写入的数据库:<logger name="*" minlevel="Info" writeTo="DbSqlServer" />
启动项目,通过 Swagger 调用 SecondController 中的 index() 方法。
调用后查看 t_nlog 表,发现日志输出失败,没有查到任何记录。
原因是在 NuGet 包管理器中安装的 NLog 程序集的版本太高了,需要将之更新到 4.x 版本。
NLog 的 5.x 版本以后,写入数据库日志的方法有所改变,以后有时间再对配置文件适配 5.x 版本的 NLog。
更新完成后,重新启动项目,再通过 Swagger 调用 SecondController 中的 index() 方法。
调用后查看 t_nlog 表,发现本次日志输出成功。
调用后查看 t_nlog 表,发现本次日志输出成功。
先在项目上 “右键——管理 NuGet 程序包”,在浏览中搜索:MySql.Data,并安装。
在 MySQL 数据库中创建 t_nlog 表,设置 id 为自增。
create table t_nlog(
id int primary key auto_increment comment 'id',
application varchar(55) comment 'AspNetCoreNlog',
logged datetime comment '日志时间',
log_level varchar(36) comment '日志等级',
message varchar(4000) comment '日志信息',
logger varchar(255) comment '触发日志的对象',
call_site varchar(255) comment '执行日志的代码行信息',
exception varchar(2000) comment '异常信息'
) comment = 'nlog 日志表';
在 Nlog 的配置文件中,增加对 MySQL 数据库的配置。
<!-- 将日志写入 MySQL 数据库 -->
<!-- 数据库中表的字段,需要与下面配置中的一致 -->
<target xsi:type="Database" name="DbMySQL"
dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"
connectionString="server=192.168.1.2;uid=root;pwd=123456;port=3306;database=test;SslMode=none"
commandText="insert into t_nlog(application,logged,log_level,message,logger,call_site,exception) values(@application,@logged,@logLevel,@message,@logger,@callSite,@exception)">
<parameter name="@application" layout="AspNetCoreNlog" />
<parameter name="@logged" layout="${date}" />
<parameter name="@logLevel" layout="${level}" />
<parameter name="@message" layout="${message}" />
<parameter name="@logger" layout="${logger}" />
<parameter name="@callSite" layout="${callsite:filename=true}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
配置完成后,在配置文件的 rules 标签中指定需要写入的数据库:<logger name="*" minlevel="Info" writeTo="DbMySQL" />
启动项目,通过 Swagger 调用 SecondController 中的 index() 方法。
调用后查看 t_nlog 表,日志写入到 MySQL 数据库成功。