.Net6 Web Core API --- AOP -- log4net 封装 -- MySQL -- txt

news2024/11/18 11:18:04

目录

一、引入 NuGet 包

二、配置log4net.config  

三、编写Log4net封装类

四、编写日志记录类

五、AOP -- 拦截器 -- 封装

六、案例编写

七、结果展示


一、引入 NuGet 包

log4net 

Microsoft.Extensions.Logging.Log4Net.AspNetCore   

MySql.Data         ----  MySQL数据库需要

Newtonsoft.Json

Autofac

Autofac.Extensions.DependencyInjection

Autofac.Extras.DynamicProxy

二、配置log4net.config  

    注:当前网上有两种 log4net.config 配置文件, 一种是以<log4net>为根目录, 另一种以<configuration> 为根目录

<?xml version="1.0" encoding="utf-8"?>

<log4net>
    <!--正常日志:::记录正常日志-->
    <!-- appender 定义日志输出方式   将日志以回滚文件的形式写到MySQL数据库中。-->
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
        <!-- 代表缓存大小,在没达到缓存大小时,暂时不会存到数据库中, -->
        <!-- 当程序关闭之后,会将未插入的信息加入到数据库中 -->
        <bufferSize value="1" />

        <!--引入《MySql.Data》包-->
        <param name="ConnectionType" value="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" />
        <!--配置连接数据库的字符串-->
        <param name="ConnectionString" value="server=localhost;database=TTTTT;uid=root;pwd=123456;"/>
        <!--配置MySQL的插入语句-->
        <param name="CommandText" value="insert into log4net(log_datetime,log_thread,log_level,log_logger,log_message) 
                                         values(@log_datetime, @log_thread , @log_level, @log_logger, @log_message)" />

        <param name="Parameter">
            <param name="ParameterName" value="@log_datetime" />
            <param name="DbType" value="DateTime" />
            <param name="Layout" type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%d{yyyy'-'MM'-'dd HH':'mm':'ss}" />
            </param>
        </param>

        <param name="Parameter">
            <param name="ParameterName" value="@log_thread" />
            <param name="DbType" value="String" />
            <param name="Size" value="255" />
            <param name="Layout" type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%t" />
            </param>
        </param>

        <param name="Parameter">
            <param name="ParameterName" value="@log_level" />
            <param name="DbType" value="String" />
            <param name="Size" value="255" />
            <param name="Layout" type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%p" />
            </param>
        </param>

        <param name="Parameter">
            <param name="ParameterName" value="@log_logger" />
            <param name="DbType" value="String" />
            <param name="Size" value="255" />
            <param name="Layout" type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%c" />
            </param>
        </param>

        <param name="Parameter">
            <param name="ParameterName" value="@log_message" />
            <param name="DbType" value="String" />
            <param name="Size" value="4000" />
            <param name="Layout" type="log4net.Layout.PatternLayout">
                <param name="ConversionPattern" value="%m" />
            </param>
        </param>

    </appender>

    <!--正常日志:::记录正常日志-->
    <!--按日期分割日志文件 一天一个-->
    <!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
        <!-- 定义中文编码类型  UTF-8-->
        <param name="Encoding" value="utf-8" />
        <!--定义文件存放位置-->
        <file value="Log\log_"/>
        <!--是否追加到文件-->
        <appendToFile value="true"/>
        <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
        <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
        <maxSizeRollBackups value="-1"/>
        <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
        <rollingStyle value="Composite"/>
        <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/>
        <!--是否只写到一个文件中-->
        <staticLogFileName value="false"/>
        <!--每个文件的大小。只在混合方式与文件大小方式下使用。
    超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。
    可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
        <maximumFileSize value="100MB"/>
        <!--计数类型为1,2,3…-->
        <!--<param name="CountDirection" value="1"/>-->
        <layout type="log4net.Layout.PatternLayout">
            <!--输出格式-样例:
            记录时间:2022-08-24 17:59:31,172    线程ID:[4]    日志级别:INFO  当前类:Log4NetDemo.MainClass  
            日志描述:创建连接。-->
            <conversionPattern value="记录时间:%date  线程ID:[%thread]  日志级别:%-5level 当前类:%logger %newline日志描述:%message  %newline %newline"/>
        </layout>
    </appender>

    <!--错误日志:::记录错误日志-->
    <!--按日期分割日志文件 一天一个-->
    <!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
        <!-- 定义中文编码类型  UTF-8-->
        <param name="Encoding" value="utf-8" />
        <!--定义文件存放位置-->
        <file value="Log\error_"/>
        <!--是否追加到文件-->
        <appendToFile value="true"/>
        <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
        <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
        <maxSizeRollBackups value="-1"/>
        <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
        <rollingStyle value="Composite"/>
        <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/>
        <!--是否只写到一个文件中-->
        <staticLogFileName value="false"/>
        <!--每个文件的大小。只在混合方式与文件大小方式下使用。
    超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。
    可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
        <maximumFileSize value="100MB"/>
        <!-- layout 控制Appender的输出格式,也可以是xml  一个Appender只能是一个layout-->
        <layout type="log4net.Layout.PatternLayout">
            <!--每条日志末尾的文字说明-->
            <!--输出格式 模板-->
            <!-- <param name="ConversionPattern"  value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger   
    操作者ID:%property{Operator} 操作类型:%property{Action}%n  当前机器名:%property%n当前机器名及登录用户:%username %n  
    记录位置:%location%n 消息描述:%property{Message}%n   异常:%exception%n 消息:%message%newline%n%n" />-->

            <!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->
            <!--<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n错误描述:%message%newline %n"/>-->
            <conversionPattern value="%n==========
                              %n【日志级别】%-5level
                              %n【记录时间】%date
                              %n【执行时间】[%r]毫秒
                              %n【错误位置】%logger 属性[%property{NDC}]
                              %n【错误描述】%message
                              %n【错误详情】%newline"/>
        </layout>
        <filter type="log4net.Filter.LevelRangeFilter,log4net">
            <levelMin value="ERROR" />
            <levelMax value="FATAL" />
        </filter>
    </appender>

    <!--DEBUG:::记录DEBUG日志-->
    <!--按日期分割日志文件 一天一个-->
    <!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
    <appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
        <!-- 定义中文编码类型  UTF-8-->
        <param name="Encoding" value="utf-8" />
        <!--定义文件存放位置-->
        <file value="Log\debug_"/>
        <!--是否追加到文件-->
        <appendToFile value="true"/>
        <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
        <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
        <maxSizeRollBackups value="-1"/>
        <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
        <rollingStyle value="Composite"/>
        <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/>
        <!--是否只写到一个文件中-->
        <staticLogFileName value="false"/>
        <!--每个文件的大小。只在混合方式与文件大小方式下使用。
    超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。
    可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
        <maximumFileSize value="100MB"/>
        <!-- layout 控制Appender的输出格式,也可以是xml  一个Appender只能是一个layout-->
        <layout type="log4net.Layout.PatternLayout">
            <!--输出格式-样例:
            记录时间:2022-08-24 17:59:31,172    线程ID:[4]    日志级别:INFO  当前类:Log4NetDemo.MainClass  
            日志描述:创建连接。-->
            <conversionPattern value="记录时间:%date  线程ID:[%thread]  日志级别:%-5level 当前类:%logger %newline日志描述:%message  %newline %newline"/>
        </layout>
        <filter type="log4net.Filter.LevelRangeFilter,log4net">
            <levelMin value="DEBUG" />
            <levelMax value="WARN" />
        </filter>
    </appender>

    <root>
        <!--日志等级:OFF > FATAL > ERROR > WARN > INFO > DEBUG  > ALL-->
        <level value="ALL" />
        <appender-ref ref="ADONetAppender" />
        <appender-ref ref="RollingFile" />
        <appender-ref ref="ErrorAppender" />
        <appender-ref ref="DebugAppender" />
    </root>

</log4net>

三、编写Log4net封装类

public static class CustomLog4netExt
{
    public static void AddLog4netExt(this WebApplicationBuilder builder)
    {
        // 添加 Log4net 配置文件
        builder.Logging.AddLog4Net("log4net.config");
        
        // log错误日志配置
        builder.Services.AddControllers(options =>
        {
            options.SuppressAsyncSuffixInActionNames = false;
            
            options.Filters.Add(typeof(GlobalExceptionsFilter));
        });
    }
}

四、编写日志记录类

全局报错监测类

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Log4Test.Log4;

/// <summary>
/// 全局异常错误日志
/// </summary>
public class GlobalExceptionsFilter : IExceptionFilter
{
    private readonly IWebHostEnvironment _env;
    private readonly ILogger<GlobalExceptionsFilter> _logger;

    public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger<GlobalExceptionsFilter> logger)
    {
        _env = env;
        _logger = logger;
    }
    public void OnException(ExceptionContext context)
    {
        var json = new JsonErrorResponse();
        json.Message = context.Exception.Message;//错误信息
        if (_env.IsDevelopment())
        {
            json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息
        }
        context.Result = new InternalServerErrorObjectResult(json);

        //采用log4net 进行错误日志记录
        _logger.LogError(WriteLog(json.Message, context.Exception));
    }

    /// <summary>
    /// 自定义返回格式
    /// </summary>
    /// <param name="throwMsg"></param>
    /// <param name="ex"></param>
    /// <returns></returns>
    public string WriteLog(string throwMsg, Exception ex)
    {
        return string.Format("【自定义错误】:{0} \r\n" +
                             "【异常类型】:{1} \r\n" +
                             "【异常信息】:{2} \r\n" +
                             "【堆栈调用】:{3}", 
                             new object[] { 
                                 throwMsg,
                                 ex.GetType().Name, 
                                 ex.Message, 
                                 ex.StackTrace 
                             });
    }

}

public class InternalServerErrorObjectResult : ObjectResult
{
    public InternalServerErrorObjectResult(object value) : base(value)
    {
        StatusCode = StatusCodes.Status500InternalServerError;
    }
}
//返回错误信息
public class JsonErrorResponse
{
    /// <summary>
    /// 生产环境的消息
    /// </summary>
    public string Message { get; set; }
    /// <summary>
    /// 开发环境的消息
    /// </summary>
    public string DevelopmentMessage { get; set; }
}

日常方法监测类

using Castle.DynamicProxy;
using Newtonsoft.Json;

namespace LOG.Test;

/// <summary>
/// 自定义 方法拦截器
/// </summary>
public class CustomInterceptor : IInterceptor
{
    private readonly ILogger<CustomInterceptor> _logger;

    public CustomInterceptor(ILogger<CustomInterceptor> logger)
    {
        _logger = logger;
    }

    public void Intercept(IInvocation invocation)
    {
        string result = $"开始执行-->\n方法名: {invocation.Method.Name}\n";
        
        foreach (var item in invocation.Arguments)
        {
            result += $"入参---{JsonConvert.SerializeObject(item)}\n";
        }
        
        _logger.LogInformation(result);
        
        invocation.Proceed();
        
        _logger.LogInformation($"结束执行-->\n方法名: {invocation.Method.Name}\n" +
                                      $"返回结果---{JsonConvert.SerializeObject(invocation.ReturnValue)}\n");
    }
}

五、AOP -- 拦截器 -- 封装

using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;

namespace LOG.Test;

public static class CustomAOPExt
{
    public static void AddAOPExt(this WebApplicationBuilder builder)
    {
        
        builder.Host
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())  // 工厂替换,把Autofac整合进来
            .ConfigureContainer<ContainerBuilder>(containerBuilder =>
            {
                // 依赖注入
                containerBuilder.RegisterType<CustomInterceptor>(); 
                containerBuilder.RegisterType<Student>().As<IStudent>().EnableClassInterceptors(); // 开启类拦截器 
                //containerBuilder.RegisterType<Student>().As<IStudent>().EnableInterfaceInterceptors(); // 开启接口拦截器
            });
    }
}

六、案例编写

// 在Program.cs 中

// 添加 lg4net 扩展
builder.AddLog4netExt();
// 添加 AOP 扩展
builder.AddAOPExt();

创建 Student 和 IStudent  测试类和接口

 创建 一个 控制器

七、结果展示

 


如有错误,烦请批评指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/837039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

好用的智能ai绘画文字转绘画软件大揭秘

在一个平凡的小镇上&#xff0c;有一位名叫李彤的年轻画家。她对绘画充满了热爱和渴望。但因为经济条件有限&#xff0c;无法承担昂贵的绘画软件费用。然而&#xff0c;就在她感到困惑和单调的文字转换为令人惊叹的绘画作品&#xff0c;让每一位渴望艺术表达的人都能轻松实现自…

css实现卡片的左上角有一个三角形的遮盖效果

需求: 卡片的左上角有一个绿色的三角形标签,用来区分状态 实现: .vCard{position: relative;overflow: hidden; } .vCard::before {content: "";position: absolute;top: 0;left: 0;width: 0;height: 0;border-bottom: 20px solid transparent;border-left: 20px …

直线模组在机械手中的应用

机械手是一种能模仿人手和臂的某些动作功能&#xff0c;用以按固定程序抓取、搬运物件或操作工具的自动操作装置&#xff0c;可代替人的繁重劳动以实现生产的机械化和自动化&#xff0c;能在有害环境下操作以保护人身安全&#xff0c;因而广泛应用于机械制造、冶金、电子、轻工…

创新赛制,顶尖赛题!| 2023第二届粤港澳大湾区(黄埔)国际算法算例大赛十赛道虚位以待!

2023 第二届“粤港澳大湾区&#xff08;黄埔&#xff09;国际算法算例大赛”&#xff08;以下简称“大赛”&#xff09;于 2023 年 7 月 15 日正式开赛。大赛面向全球&#xff0c;诚邀有创新精神&#xff0c;并有较好的AI算法算例基础的高校学生、AI领域相关企业和研究院所的从…

硬件串口通信协议学习(UART、IIC、SPI、CAN)

0.前言 学习资料&#xff1a;江协科技的个人空间-江协科技个人主页-哔哩哔哩视频 通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 全双工&#xff1a;通信…

寄件管理系统设置教程

“企业寄件管理系统”或许是个小众词汇&#xff0c;但是“企业寄件”却是各家公司都不陌生的词汇。在经济和快递发展的双重影响之下&#xff0c;企业寄件早已成为企业运转的日常事项之一&#xff0c;企业寄件管理也越发被企业管理者所重视。我们对企业管理系统并不陌生&#xf…

go 基本语法(简单案例)

&#xff01;注&#xff1a; go中 对变量申明很是严格&#xff0c;申明了&#xff0c;在没有使用的情况下&#xff0c;也会产生编译错误 1.行分隔符 一行就是代码&#xff0c;无&#xff1b;分割&#xff0c;如果需要在一行展示&#xff0c;需要以&#xff1b;分割&#xff0c;…

短信端口和端口短信的概念

什么是端口短信 端口短信是针对点到点短信来说的,点到点即手机直接发给手机的,端口就是使用软件发给手机的。软件是移动运营商合作的内容提供商开发的,遵守运营商的规范,有端口号。 短信端口是什么意思? 是针对点到点短信来说的,点对点即手机直接发给手机的,端口就是使用软…

C# PaddleDetection 版面分析

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using Sdcb.PaddleDetection; using Sdcb.PaddleInference; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Lin…

java:JUnit单元测试

背景 一般软件测试分为白盒测试和黑盒测试 黑盒测试&#xff1a;就是现在一般测试人员的工作点点点&#xff0c;只要功能正常就行白盒测试&#xff1a;需要关注代码的具体执行过程&#xff0c;是需要写代码的 JUnit 框架是进行白盒测试使用的。 不使用单元测试框架 没有单…

看一家头部实干派互娱公司如何玩转DataOps?

DataOps的概念自首次被提出至今已有8年&#xff0c;并在2018年被Gartner纳入数据管理技术成熟度曲线。从实施上看&#xff0c;当下DataOps仍处在发展初期&#xff0c;鲜少企业或团队能据此真正沉淀一套方法论或技术产品的体系。不过&#xff0c;随着越来越多的企业开启DataOps实…

【flink】使用flink-web-ui提交作业报错

使用WebUI提交作业出现错误。 错误截图&#xff1a; 弹框信息&#xff1a; Server Response Message: org.apache.flink.runtime.rest.handler.RestHandlerException: Could not execute application.at org.apache.flink.runtime.webmonitor.handlers.JarRunHandler.lambda$h…

行业追踪,2023-08-04

自动复盘 2023-08-04 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

idea使用protobuf

本文参考&#xff1a;https://blog.csdn.net/m0_37695902/article/details/129438549 再次感谢分享 什么是 protobuf &#xff1f; Protocal Buffers(简称protobuf)是谷歌的一项技术&#xff0c;用于结构化的数据序列化、反序列化。 由于protobuf是跨语言的&#xff0c;所以用…

进程与线程、线程创建、线程周期、多线程安全和线程池(ThreadPoolExecutor)

目录 进程与线程线程和进程的区别是什么&#xff1f;线程分两种&#xff1a;用户线程和守护线程线程创建四种方式run()和start()方法区别&#xff1a;为什么调用 start() 方法时会执行 run() 方法&#xff0c;为什么不能直接调用 run() 方法&#xff1f;Runnable接口和Callable…

最强实战,接口自动化测试Python3+Requests+Unittest+ddt框架封装(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 接口自动化测试框…

RDP远程桌面服务的RD授权过期解决方法

RDP远程桌面服务的RD授权过期解决方法 一、打开远程桌面会话主机配置二、打开远程桌面授权模式属性三、选择远程桌面授权模式四、添加许可证服务器五、选择确定保存设置六、RD授权设置成功七、查看“授权诊断” 一、打开远程桌面会话主机配置 二、打开远程桌面授权模式属性 双…

35岁,不是体能衰老的分界线!

35岁&#xff0c;不是体能衰老的分界线 1. 35岁以上求职者同比增长14.9%&#xff0c;体能下滑成为35岁以上年龄群体的标签。 2. 35岁人群开始感觉经常失眠、腰背痛和肥胖&#xff0c;体力不济可能是常年累积的不规律作息和饮食习惯导致。 3. 35岁以后体能下滑&#xff0c;无法高…

视频添加字幕

1、依靠ffmpeg 命令 package zimu;import java.io.IOException;public class TestSrt {public static void main(String[] args) {String videoFile "/test/test1.mp4";String subtitleFile "/test/test1.SRT";String outputFile "/test/testout13…

openpnp - 吸嘴站(Nozzle Tip Changer)的选择

文章目录 openpnp - 吸嘴站(Nozzle Tip Changer)的选择概述磁铁吸嘴库带抱轴的吸嘴库我的吸嘴库选择我的吸嘴库实现 - 磁铁吸嘴库吸嘴座主体吸嘴座上盖我的吸嘴库实现 - 带抱轴的吸嘴库吸嘴座主体拔吸嘴时的受力挡板抱轴层上盖备注END openpnp - 吸嘴站(Nozzle Tip Changer)的选…