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/&quot;log.log&quot;" />

        <!--日志最大个数,都是最新的-->
        <!--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/&quot;error.log&quot;" />
        <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/&quot;log.log&quot;" />

        <!--日志最大个数,都是最新的-->
        <!--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/&quot;error.log&quot;" />
        <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

posted @ 2023-07-21 15:46  无心々菜  阅读(693)  评论(0编辑  收藏  举报