.net8系列-05图文并茂手把手教你配置日志组件log4net
log4net是什么?
log4net是Apache软件基金会为.NET平台开发的一个日志记录库。它是Apache log4j框架的.NET移植版本,属于Apache Logging Services项目的一部分。
为什么使用log4net?
log4net设计用于帮助.NET应用程序的开发者控制日志信息的生成过程,使得日志信息可以根据配置被输出到多种目的地,包括控制台、文件系统、数据库、电子邮件、Windows事件日志等。
log4net有什么特点?
分级日志级别:支持DEBUG、INFO、WARN、ERROR、FATAL等多个日志级别,允许开发者精细控制输出哪些信息。
灵活的配置:强大的XML配置文件支持,可以在不修改代码的情况下调整日志行为。
多种输出目标:支持多种日志信息的目的地,易于扩展。
定制化布局:可以定制日志信息的格式,如添加时间戳、线程信息等。
性能优化:通过缓冲和异步写入等机制减少日志记录对应用程序性能的影响。
log4net怎么用?
安装log4net解决方案包
安装Microsoft.Extensions.Logging.Log4Net.解决方案包
编写配置文件
xiaojinWebApplication\xiaojinWebApplication\configFile\log4net.Config
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!-- Define some output appenders -->
<appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
<file value="log4\log.txt" />
<!--追加日志内容-->
<appendToFile value="true" />
<!--防止多线程时不能写Log,官方说线程非安全-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<!--可以为:Once|Size|Date|Composite-->
<!--Composite为Size和Date的组合-->
<rollingStyle value="Composite" />
<!--当备份文件时,为文件名加的后缀-->
<datePattern value="yyyyMMdd.TXT" />
<!--日志最大个数,都是最新的-->
<!--rollingStyle节点为Size时,只能有value个日志-->
<!--rollingStyle节点为Composite时,每天有value个日志-->
<maxSizeRollBackups value="20" />
<!--可用的单位:KB|MB|GB-->
<maximumFileSize value="3MB" />
<!--置为true,当前最新日志文件名永远为file节中的名字-->
<staticLogFileName value="true" />
<!--输出级别在INFO和ERROR之间的日志-->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ALL" />
<param name="LevelMax" value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<!--SqlServer形式-->
<!--log4net日志配置:http://logging.apache.org/log4net/release/config-examples.html -->
<appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender">
<!--日志缓存写入条数 设置为0时只要有一条就立刻写到数据库-->
<bufferSize value="0" />
<connectionType value="System.Data.SqlClient.SqlConnection,System.Data.SqlClient, Version=4.6.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<connectionString value="Data Source=PC-202206030027;Initial Catalog=LogManager;Persist Security Info=True;User ID=sa;Password=sa123" />
<commandText value="INSERT INTO Log4Net ([Date],[Thread],[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>
<!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
<!--OFF:0-->
<!--FATAL:FATAL-->
<!--ERROR: ERROR,FATAL-->
<!--WARN: WARN,ERROR,FATAL-->
<!--INFO: INFO,WARN,ERROR,FATAL-->
<!--DEBUG: INFO,WARN,ERROR,FATAL-->
<!--ALL: DEBUG,INFO,WARN,ERROR,FATAL-->
<priority value="ALL"/>
<level value="INFO"/>
<appender-ref ref="rollingAppender" />
<appender-ref ref="AdoNetAppender_SqlServer" />
</root>
</log4net>
暂时注释数据库日志,等到我们链接数据库后我们再进行使用
注释root里的AdoNetAppender_SqlServer
<root>
<!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
<!--OFF:0-->
<!--FATAL:FATAL-->
<!--ERROR: ERROR,FATAL-->
<!--WARN: WARN,ERROR,FATAL-->
<!--INFO: INFO,WARN,ERROR,FATAL-->
<!--DEBUG: INFO,WARN,ERROR,FATAL-->
<!--ALL: DEBUG,INFO,WARN,ERROR,FATAL-->
<priority value="ALL"/>
<level value="INFO"/>
<appender-ref ref="rollingAppender" />
<!-- <appender-ref ref="AdoNetAppender_SqlServer" /> -->
</root>
配置NLog.Config
xiaojinWebApplication\xiaojinWebApplication\configFile\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"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<!-- optional, add some variables
https://github.com/nlog/NLog/wiki/Configuration-file#variables
-->
<variable name="myvar" value="myvalue"/>
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<!--
add your targets here
See https://github.com/nlog/NLog/wiki/Targets for possible targets.
See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
-->
<target name="AllDatabase" xsi:type="Database"
dbProvider="System.Data.SqlClient.SqlConnection, System.Data.SqlClient"
connectionString="Data Source=PC-202206030027;Initial Catalog=LogManager;Persist Security Info=True;User ID=sa;Password=sa123"
commandText="insert into dbo.NLog (Application, Logged, Level, Message,Logger, CallSite, Exception) values (@Application, @Logged, @Level, @Message,@Logger, @Callsite, @Exception);">
<parameter name="@application" layout="AspNetCoreNlog" />
<parameter name="@logged" layout="${date}" />
<parameter name="@level" 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>
<target xsi:type="File" name="allfile" fileName="NLog\nlog-all-${shortdate}.log"
layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
<!--同样是将文件写入日志中,写入的内容有所差别,差别在layout属性中体现。写入日志的数量有差别,差别在路由逻辑中体现-->
<target xsi:type="File" name="ownFile-web" fileName="NLog\nlog-my-${shortdate}.log"
layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
<target xsi:type="Null" name="blackhole" />
<!--
Write events to a file with the date in the filename.
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="AllDatabase" />
<!-- add your logging rules here -->
<!--路由顺序会对日志打印产生影响。路由匹配逻辑为顺序匹配。-->
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile" />
<!--Skip Microsoft logs and so log only own logs-->
<!--以Microsoft打头的日志将进入此路由,由于此路由没有writeTo属性,所有会被忽略-->
<!--且此路由设置了final,所以当此路由被匹配到时。不会再匹配此路由下面的路由。未匹配到此路由时才会继续匹配下一个路由-->
<logger name="Microsoft.*" minlevel="Trace" final="true" />
<!--上方已经过滤了所有Microsoft.*的日志,所以此处的日志只会打印除Microsoft.*外的日志-->
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
<!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" />
-->
</rules>
</nlog>
设置编译属性
右键两个配置文件,改为始终编译
配置日志生效逻辑
在Program.cs文件中注册
// log4net---start
builder.Logging.AddLog4Net("configFile/log4net.Config");
// log4net---end
日志使用:构造函数注入
在测试接口文件中添加如下代码(我这个已经有了哦)
private readonly ILogger<CommonInfoController> _logger;
public CommonInfoController(ILogger<CommonInfoController> logger)
{
_logger = logger;
}
添加日志测试代码
public CommonInfoController(ILogger<CommonInfoController> logger)
{
_logger = logger;
_logger.LogInformation(" LogInformation; this is CommonInfoController 构造函数~");
_logger.LogError("LogError: this is CommonInfoController 构造函数~");
_logger.LogWarning("LogWarning: this is CommonInfoController 构造函数~");
_logger.LogDebug("LogDebug:this is CommonInfoController 构造函数~");
}
第二种用法
private readonly ILogger<CommonInfoController> _logger; // 方案一
private readonly ILoggerFactory _ILoggerFactory; // 方案二
public CommonInfoController(ILogger<CommonInfoController> logger, ILoggerFactory iLoggerFactory)
{
_logger = logger;
_logger.LogInformation("方案一 LogInformation; this is CommonInfoController 构造函数~");
_logger.LogError("方案一LogError: this is CommonInfoController 构造函数~");
_logger.LogWarning("方案一LogWarning: this is CommonInfoController 构造函数~");
_logger.LogDebug("方案一LogDebug:this is CommonInfoController 构造函数~");
_ILoggerFactory = iLoggerFactory; // 方案二
ILogger<CommonInfoController> _loger2 = _ILoggerFactory.CreateLogger<CommonInfoController>();
_loger2.LogInformation("方案二LogInformation; this is CommonInfoController 构造函数~");
_loger2.LogError("方案二LogError: this is CommonInfoController 构造函数~");
_loger2.LogWarning("方案二LogWarning: this is CommonInfoController 构造函数~");
_loger2.LogDebug("方案二LogDebug:this is CommonInfoController 构造函数~");
}
接口中记录日志
/// <summary>
/// 测试接口01
/// </summary>
/// <returns></returns>
[HttpGet(Name = "getCommonInfo")]
public CommonInfo getCommonInfo()
{
_logger.LogInformation("测试接口01~");
_logger.LogError("测试接口01~");
_logger.LogWarning("测试接口01~");
_logger.LogDebug("测试接口01~");
return new CommonInfo
{
Date = DateOnly.FromDateTime(DateTime.Now),
Text = "getCommonInfo"
};
}
启动项目
调用接口
查看日志
根据我们的配置项,日志在这个地方存储:"\xiaojinWebApplication\bin\Debug\net8.0\log4\log.txt"
2024-04-30 01:29:51,143 [1] INFO Microsoft.Hosting.Lifetime - Now listening on: http://localhost:5064
2024-04-30 01:29:51,153 [1] INFO Microsoft.Hosting.Lifetime - Application started. Press Ctrl+C to shut down.
2024-04-30 01:29:51,154 [1] INFO Microsoft.Hosting.Lifetime - Hosting environment: Development
2024-04-30 01:29:51,155 [1] INFO Microsoft.Hosting.Lifetime - Content root path: C:\Users\testDemo\net-demo\xiaojinWebApplication\xiaojinWebApplication
2024-04-30 01:30:17,271 [7] INFO xiaojinWebApplication.Controllers.CommonInfoController - 方案一 LogInformation; this is CommonInfoController 构造函数~
2024-04-30 01:30:17,279 [7] ERROR xiaojinWebApplication.Controllers.CommonInfoController - 方案一LogError: this is CommonInfoController 构造函数~
2024-04-30 01:30:17,281 [7] WARN xiaojinWebApplication.Controllers.CommonInfoController - 方案一LogWarning: this is CommonInfoController 构造函数~
2024-04-30 01:30:17,282 [7] INFO xiaojinWebApplication.Controllers.CommonInfoController - 方案二LogInformation; this is CommonInfoController 构造函数~
2024-04-30 01:30:17,285 [7] ERROR xiaojinWebApplication.Controllers.CommonInfoController - 方案二LogError: this is CommonInfoController 构造函数~
2024-04-30 01:30:17,287 [7] WARN xiaojinWebApplication.Controllers.CommonInfoController - 方案二LogWarning: this is CommonInfoController 构造函数~
2024-04-30 01:30:17,289 [7] INFO xiaojinWebApplication.Controllers.CommonInfoController - 测试接口01~
2024-04-30 01:30:17,290 [7] ERROR xiaojinWebApplication.Controllers.CommonInfoController - 测试接口01~
2024-04-30 01:30:17,291 [7] WARN xiaojinWebApplication.Controllers.CommonInfoController - 测试接口01~
大功告成
结语
- 今天就写到这里啦~
- 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
- 大家要天天开心哦
欢迎大家指出文章需要改正之处~
学无止境,合作共赢