|
主题设置

卡片式面板通常用于非白色背景色的主体内

日志组件

在 Web API开发中,日志组件是非常重要的一部分,它可以帮助开发者跟踪和记录 API 的运行过程,以便进行故障排除、性能优化和安全审计。

log4net 组件

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 中被写入日志内容。

写入 SqlServer

先在项目上 “右键——管理 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() 方法。

查看日志文件,日志写入成功。

查看数据库日志表,日志写入成功。

写入 MySQL

先在项目上 “右键——管理 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 组件

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 中只记载用户输出的日志。

这正对应着配置文件中的配置,这两个配置可根据需要进行使用,不需要的可以注释掉。

写入 SqlServer

先在项目上 “右键——管理 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 表,发现本次日志输出成功。

写入 MySQL

先在项目上 “右键——管理 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 数据库成功。