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

目录

一、引入 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.mfbz.cn/a/63409.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Embedding入门介绍以及为什么Embedding在大语言模型中很重要

Embeddings技术简介及其历史概要 在机器学习和自然语言处理中&#xff0c;embedding是指将高维度的数据&#xff08;例如文字、图片、音频&#xff09;映射到低维度空间的过程。embedding向量通常是一个由实数构成的向量&#xff0c;它将输入的数据表示成一个连续的数值空间中…

AcWing1171. 距离(lcatarjan)

输入样例1&#xff1a; 2 2 1 2 100 1 2 2 1输出样例1&#xff1a; 100 100输入样例2&#xff1a; 3 2 1 2 10 3 1 15 1 2 3 2输出样例2&#xff1a; 10 25 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N2e55; int n,m,x,y,k,r…

Android Tencent Shadow 插件接入指南

Android Tencent Shadow 插件接入指南 插件化简述一、clone 仓库二、编译运行官方demo三、发布Shadow到我们本地仓库3.1、安装Nexus 3.x版本3.2、修改发布配置3.3、发布仓库3.4、引用仓库包 四、编写我们自己的代码4.1、新建项目导入maven等共同配置4.1.1、导入buildScript4.1.…

C++ Lambda表达式的完整介绍

一、Lambda表达式概述 c在c11标准中引入了lambda表达式&#xff0c;一般用于定义匿名函数&#xff0c;lambda表达式&#xff08;也称为lambda函数&#xff09;是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。通常&#xff0c;lambda用于封装传递给算法或异步…

QT以管理员身份运行

以下配置后&#xff0c;QT在QT Creator调试时&#xff0c;或者生成的.exe程序&#xff0c;都将会默认以管理员身份运行。 一、MSVC编译器 1、在Pro文件中添加以下代码&#xff1a; QMAKE_LFLAGS /MANIFESTUAC:\"level\requireAdministrator\ uiAccess\false\\" …

vue 标题文字字数过长超出部分用...代替 动态显示

效果: 浏览器最大化: 浏览器缩小: 代码: html: <div class"title overflow">{{item.name}}</div> <div class"content overflow">{{item.content}}</div> css: .overflow {/* 一定要加宽度 */width: 90%;/* 文字的大小 */he…

JMeter命令行执行+生成HTML报告

1、为什么用命令行模式 使用GUI方式启动jmeter&#xff0c;运行线程较多的测试时&#xff0c;会造成内存和CPU的大量消耗&#xff0c;导致客户机卡死&#xff1b; 所以一般采用的方式是在GUI模式下调整测试脚本&#xff0c;再用命令行模式执行&#xff1b; 命令行方式支持在…

04-4_Qt 5.9 C++开发指南_时间日期与定时器

文章目录 1. 时间日期相关的类2. 源码2.1 可视化UI设计2.2 dialog.h2.3 dialog.cpp 1. 时间日期相关的类 时间日期是经常遇到的数据类型&#xff0c;Qt 中时间日期类型的类如下。 QTime:时间数据类型&#xff0c;仅表示时间&#xff0c;如 15:23:13。 QDate:日期数据类型&…

jmeter 5.1彻底解决中文上传乱码

1.修改源码,然后重新打jar包,就是所有上传文件名重新获取文件名 参考链接:多种Jmeter中文乱码问题处理方法 - 51Testing软件测试网 2.修改Advanced,必须选java

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--功能实现[五]

文章目录 SSM--功能实现实现功能09-带条件查询分页显示列表需求分析/图解思路分析代码实现测试分页条件查询带条件分页查询显示效果 实现功能10-添加家居表单前端校验需求分析/图解思路分析代码实现完成测试测试页面效果 实现功能11-添加家居表单后端校验需求分析/图解思路分析…

第八次作业

1、什么是数据认证&#xff0c;有什么作用&#xff0c;有哪些实现的技术手段&#xff1f; 数据认证的官方回答&#xff1a;数字认证证书它是以数字证书为核心的加密技术可以对网络上传输的信息进行加密和解密、数字签名和签名验证&#xff0c;确保网上传递信息的安全性、完整性…

Squeeze-and-Excitation Networks阅读笔记一

文章目录 Abstract1 INTRODUCTION Abstract 卷积算子&#xff08;convolution operator&#xff09;是卷积神经网络&#xff08;cnn&#xff09;的核心组成部分&#xff0c;它使网络能够通过融合每层局部接受域内的空间和通道信息来构建信息特征。广泛的先前研究已经调查了这种…

CSS调色网有哪些

本文章转载于湖南五车教育&#xff0c;仅用于学习和讨论&#xff0c;如有侵权请联系 1、https://webgradients.com/ Wbgradients 是一个在线调整渐变色的网站 &#xff0c;可以根据你想要的调整效果&#xff0c;同时支持复制 CSS 代码&#xff0c;可以更好的与开发对接。 Wbg…

今天开始学习如何正式调查

本节要讲解三个内容 样本容量 调查方式 调查问卷的回收 在正式调查之前需要确定样本容量 就说要准备调查多少人确定好样本容量之后又要考虑设计的调查问卷 是以什么样的方式发出去 问卷的回收又要注意什么问题 要讲的主要内容 先看样本容量 样本容量确定的基本原…

IO(JavaEE初阶系列8)

目录 前言&#xff1a; 1.文件 1.1认识文件 1.2结构和目录 1.3文件路径 1.4文本文件vs二进制文件 2.文件系统的操作 2.1Java中操作文件 2.2File概述 2.2.1构造File对象 2.2.2File中的一些方法 3.文件内容的操作 3.1字节流 3.1.1InPutStream的使用方法 3.1.2OutPu…

UEditorPlus v3.3.0 图片上传压缩重构,UI优化,升级基础组件

UEditor是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更符…

Unity 实现字幕打字效果

Text文本打字效果&#xff0c;TextMeshPro可以对应参考&#xff0c;差距不大&#xff0c;改改参数名就能用。改脚本原本被我集成到其他的程序集中&#xff0c;现在已经分离。 效果 实现功能 1.能够设置每行能够容纳的字数和允许的冗余 2.打字效果 3.每行打完上移 4.开头进入&…

Markdown系列之Flowchat流程图

一.欢迎来到我的酒馆 介绍Markdown的Flowchart流程图语法。 目录 一.欢迎来到我的酒馆二.什么是Flowchart三.更进一步 二.什么是Flowchart 2.1 Flowchart是一款基于javascript的工具&#xff0c;使用它可以用代码创建简单的流程图。具体信息可以查看flowchart官网&#xff1a;…

栈和队列的实现

Lei宝啊&#xff1a;个人主页&#xff08;也许有你想看的&#xff09; 愿所有美好不期而遇 前言 &#xff1a; 栈和队列的实现与链表的实现很相似&#xff0c;新瓶装旧酒&#xff0c;没什么新东西。 可以参考这篇文章&#xff1a; -------------------------无头单向不循环…

微信小程序开发【从0到1~入门篇】2023.08

一个小程序主体部分由三个文件组成&#xff0c;必须放在项目的根目录&#xff0c;如下&#xff1a; 文件必须作用app.js是小程序逻辑app.json是小程序公告配置app.wxss否小程序公告样式表 3. 小程序项目结构 一个小程序页面由四个文件组成&#xff0c;分别是&#xff1a; 文…