NETCORE - 日志插件 Log4Net 写入数据库 Mysql 或 ElasticSearch
NETCORE - 日志插件 Log4Net 写入数据库 Mysql 或 ElasticSearch
项目环境:.NET6 WebApi ,
项目名称:NETCORE.Log4NetToMysql
1. 安装依赖包
Microsoft.Extensions.Logging.Log4Net.AspNetCore:6.1.0
2. 在项目中增加 Configs 文件夹,内增加 Log4Net.config 配置文件
注:文件属性设置成【始终复制】
<?xml version="1.0" encoding="utf-8"?> <log4net> <!-- Define some output appenders --> <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"> <!-- value="logs/log.log"--> <file value="logs/" /> <!--追加日志内容--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--可以为:Once|Size|Date|Composite--> <!--Composite为Size和Date的组合--> <rollingStyle value="Composite" /> <!--当备份文件时,为文件名加的后缀--> <datePattern value="yyyyMMdd/"log.log"" /> <!--日志最大个数,都是最新的--> <!--rollingStyle节点为Size时,只能有value个日志--> <!--rollingStyle节点为Composite时,每天有value个日志--> <maxSizeRollBackups value="20" /> <!--可用的单位:KB|MB|GB--> <maximumFileSize value="3MB" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="false" /> <!--输出级别在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> <!-- error日志 --> <appender name="errorAppender" type="log4net.Appender.RollingFileAppender"> <file value="logs/" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <rollingStyle value="Composite" /> <datePattern value="yyyyMMdd/"error.log"" /> <maxSizeRollBackups value="20" /> <maximumFileSize value="3MB" /> <staticLogFileName value="false" /> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="ERROR" /> <param name="LevelMax" value="ERROR" /> </filter> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/> </layout> </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"/> <!--使用上面配置的那个规则,ref指定上面的规则名称--> <appender-ref ref="rollingAppender" /> <appender-ref ref="errorAppender" /> </root> </log4net>
3. 注入,在Program.cs 文件内
builder.Logging.AddLog4Net("Configs/log4net.config");
//1.过滤掉系统默认的一些日志
//2.这里配置后,appsettings.json中的Logging配置将失效
builder.Logging.AddFilter("System", LogLevel.Error); //只有错误时才打印日志
builder.Logging.AddFilter("Microsoft", LogLevel.Error); //只有错误时才打印日志
builder.Logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Error); //只有错误时才打印日志
builder.Logging.AddFilter("MyShopApi", LogLevel.Debug); //自定义项目过滤级别,使用项目命名空间
4. 测试接口
namespace SendFileStream.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly ILogger<ValuesController> LoggerValue; public ValuesController(ILogger<ValuesController> logger) { this.LoggerValue = logger; } [HttpGet] public string Get() { LoggerValue.LogInformation($"{this.GetType()},info,接口访问"); LoggerValue.LogError($"{this.GetType()},error,接口访问错误"); return "cc"; } } }
5. 查看文件
6. 写入数据库
1) 创建数据库表
CREATE TABLE `logs` ( `log_id` bigint NOT NULL AUTO_INCREMENT, `app_name` varchar(100) NOT NULL, `log_date` datetime NOT NULL, `thread` varchar(100) NOT NULL, `level` varchar(50) NOT NULL, `logger` varchar(255) NOT NULL, `message` varchar(1000) NOT NULL, `exception` varchar(2000) NOT NULL, PRIMARY KEY (`log_id`) ) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2) 引入Nuget包
MySql.Data,注意版本号应与 NETCORE 版本一致
3) 修改配置文件,增加数据库写入配置,完整文件如下
修改数据库连接
<?xml version="1.0" encoding="utf-8"?> <log4net> <!-- Define some output appenders --> <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"> <!-- value="logs/log.log"--> <file value="logs/" /> <!--追加日志内容--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--可以为:Once|Size|Date|Composite--> <!--Composite为Size和Date的组合--> <rollingStyle value="Composite" /> <!--当备份文件时,为文件名加的后缀--> <datePattern value="yyyyMMdd/"log.log"" /> <!--日志最大个数,都是最新的--> <!--rollingStyle节点为Size时,只能有value个日志--> <!--rollingStyle节点为Composite时,每天有value个日志--> <maxSizeRollBackups value="20" /> <!--可用的单位:KB|MB|GB--> <maximumFileSize value="3MB" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="false" /> <!--输出级别在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> <!-- error日志 --> <appender name="errorAppender" type="log4net.Appender.RollingFileAppender"> <file value="logs/" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <rollingStyle value="Composite" /> <datePattern value="yyyyMMdd/"error.log"" /> <maxSizeRollBackups value="20" /> <maximumFileSize value="3MB" /> <staticLogFileName value="false" /> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="ERROR" /> <param name="LevelMax" value="ERROR" /> </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="mysqlAppender" type="log4net.Appender.AdoNetAppender"> <!--日志缓存写入条数 设置为0时只要有一条就立刻写到数据库--> <bufferSize value="0" /> <connectionType value="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" /> <connectionString value="server=127.0.0.1;database=test_db;user=root;pwd=123456;SslMode=none" /> <commandText value="INSERT INTO logs(app_name,log_date, thread, `level`, logger, message, `exception`)VALUES(@app_name,@log_date, @thread,@log_level, @logger, @message, @exception);" /> <parameter> <parameterName value="@app_name" /> <dbType value="String" /> <size value="100" /> <layout type="log4net.Layout.PatternLayout" > <conversionPattern value="api" /> </layout> </parameter> <parameter> <parameterName value="@log_date" /> <dbType value="DateTime" /> <layout type="log4net.Layout.RawTimeStampLayout" /> </parameter> <parameter> <parameterName value="@thread" /> <dbType value="String" /> <size value="100" /> <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="1000" /> <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"/> <!--使用上面配置的那个规则,ref指定上面的规则名称--> <appender-ref ref="rollingAppender" /> <appender-ref ref="errorAppender" /> <appender-ref ref="mysqlAppender" /> </root> </log4net>
4) 测试
字段扩展:
默认的数据库字段不满足需求,需要扩展字段。
参考:https://www.yii666.com/article/378880.html
1. 扩展数据库字段
在表中增加 user_id,user_ip 两个字段,注意避免 关键字 命名
alter table `logs` add `event_name` varchar(100) comment '事件名称';
2. 增加 Pattern 文件夹,增加 ActionLoggerInfo.cs 扩展类
public class ActionLoggerInfo { public string event_name { get; set; } }
3. 增加 ActionConverter.cs 类
public class ActionConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) { var actionInfo = loggingEvent.MessageObject as ActionLoggerInfo; if (actionInfo == null) { writer.Write(""); } else { switch (this.Option.ToLower()) { case "event_name": writer.Write(actionInfo.event_name); break; default: writer.Write(""); break; } } } }
4. 增加 ActionLayoutPattern.cs 类
namespace NETCORE.Log4NetToMysql.Pattern { public class ActionLayoutPattern : PatternLayout { public ActionLayoutPattern() { this.AddConverter("actionInfo", typeof(ActionConverter)); } } }
5. 修改 log4net.config 配置文件
修改sql语句:
<commandText value="INSERT INTO logs(app_name,log_date, thread, `level`, logger, message, `exception`,event_name)VALUES(@app_name,@log_date, @thread,@log_level, @logger, @message, @exception,@event_name);" />
增加参数:注意命名空间
<parameter> <parameterName value="@event_name" /> <dbType value="String" /> <size value="100" /> <layout type="NETCORE.Log4NetToMysql.Pattern.ActionLayoutPattern"> <conversionPattern value="%actionInfo{event_name}"/> </layout> </parameter>
注:如引用的其他类库项目,则使用这种方式,后面参数这类库文件 名称
<layout type="RailMeans.Log4NetExtend.ActionLayoutPattern,RailMeans"> <conversionPattern value="%actionInfo{a_user_id}"/> </layout>
6. Controller 中 测试,如未成功,可切换 mysql.data版本,重试
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly ILogger<ValuesController> LoggerValue; private readonly ILog LogValue; public ValuesController(ILogger<ValuesController> logger) { this.LoggerValue = logger; LogValue = LogManager.GetLogger("Values"); } [HttpGet] public IActionResult Get() { try { LoggerValue.LogInformation($"{this.GetType()},info,接口访问"); LoggerValue.LogError($"{this.GetType()},error,接口访问错误"); var cpm = new ActionLoggerInfo() { event_name = "ccc" }; LogValue.Info(cpm); return Ok(); } catch (Exception ex) { return BadRequest(ex.Message); } } }
写入 ElasticSearch
安装Nuget包
log4net.ElasticSearch
在 log4net.config 配置文件中增加 节点,
注意配置 server地址、索引名称、端口号等
<appender name="ElasticSearchAppender" type="log4net.ElasticSearch.ElasticSearchAppender, log4net.ElasticSearch"> <layout type="log4net.Layout.PatternLayout,log4net"> <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> </layout> <connectionString value="Server=localhost;Index=log_test;Port=9200;rolling=false"/> <lossy value="false" /> <evaluator type="log4net.Core.LevelEvaluator"> <threshold value="ALL" /> </evaluator> <bufferSize value="1" /> </appender>
在程序中使用
logger.LogInformation($"系统更新通知 - 获取未读数量,结果为:{con}");
在 Elasticsearch-head 或 kibana 中查看结果
如log4net是存在上面的扩展字段
写入到Elasticsearch中,效果如下
参考:https://blog.csdn.net/yhj198927/article/details/122238931
参考:https://www.yii666.com/article/378880.html