当前位置: 首页 > news >正文

.NetCore6.0实现ActionFilter过滤器记录接口请求日志

文章目录

  • 目的
  • 实现案例:
    • 一.首先我们新建一个WebApi项目
    • 二.配置 appsettings.json 文件,配置日志存放路径
    • 三.创建 Model 文件夹,创建AppConfig类和ErrorLog类
      • 1.在AppConfig类中编写一个GetConfigInfo方法获取配置文件中的值
      • 2.在ErrorLog类中,实现往日志文件中书写接口日志的操作
    • 四.创建Filter文件夹,创建ActionFilter实现行动过滤器,实现记录接口日志
    • 五.在 Program 中配置行动过滤器 ActionFilter
    • 六.创建一个接口,调试执行一下
  • 结果

目的

使用ActionFilter记录接口请求日志

实现案例:

https://gitee.com/hgcjd/WebApiFilter

一.首先我们新建一个WebApi项目

在这里插入图片描述

在这里插入图片描述
开发环境,我们去掉HTTPS配置
在这里插入图片描述

二.配置 appsettings.json 文件,配置日志存放路径

在这里插入图片描述

{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AppConfig": {"DirectoryPath": "项目本地日志存放路径"},"AllowedHosts": "*"
}

三.创建 Model 文件夹,创建AppConfig类和ErrorLog类

在这里插入图片描述

1.在AppConfig类中编写一个GetConfigInfo方法获取配置文件中的值

/// <summary>
/// 获取.NetCore配置文件信息
/// </summary>
public class AppConfig
{public static string GetConfigInfo(string Key){var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");IConfigurationRoot configuration = builder.Build();string configStr = configuration.GetSection($"{Key}").Value;if (!string.IsNullOrWhiteSpace(configStr)){return configStr;}return null;}}

2.在ErrorLog类中,实现往日志文件中书写接口日志的操作

public class ErrorLog
{//获取日志文件路径private static string DirectoryPath = AppConfig.GetConfigInfo("AppConfig:DirectoryPath");/// <summary>/// 写入操作日志到文件中/// </summary>/// <param name="moduleName">模块名字</param>/// <param name="message">错误文本信息</param>/// <param name="ex">异常</param>public static void Write(string message, Exception ex){string directoryPath = $@"{DirectoryPath}{DateTime.Now.ToString("yyyyMMdd")}"; // 目标目录路径if (!Directory.Exists(directoryPath)){// 如果目录不存在,则新建文件夹Directory.CreateDirectory(directoryPath);}string filePath = directoryPath + $@"\{DateTime.Now.ToString("yyyyMMddHH")}.log"; // 目标文件路径if (!File.Exists(filePath)){// 如果文件不存在,则创建文件using (File.Create(filePath)){//Console.WriteLine("文件已创建");}}LogToFile(filePath, message);}/// <summary>/// 写入操作日志到文件中/// </summary>/// <param name="moduleName">模块名字</param>/// <param name="ex">异常</param>public static void Write(string moduleName, Exception ex){Write(moduleName, moduleName, ex);}/// <summary>/// 写入过程数据或说明到文件中,以便跟踪/// </summary>/// <param name="moduleName">模块名字</param>/// <param name="ex">异常</param>public static void Write(string message){Write(String.Empty, message, null);}/// <summary>/// 文本写入/// </summary>/// <param name="logMessage"></param>private static void LogToFile(string logFilePath, string logMessage){using (StreamWriter sw = File.AppendText(logFilePath)){sw.WriteLine($"{logMessage}");}}
}

四.创建Filter文件夹,创建ActionFilter实现行动过滤器,实现记录接口日志

在这里插入图片描述

这里我们引入Newtonsoft.Json包
在这里插入图片描述

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Text.Json;
using Microsoft.Extensions.Primitives;
using WebApiTest.Model;
using System.Net.Http.Json;namespace WebApiTest.Filter
{/// <summary>/// 方法过滤器/// </summary>public class ActionFilter : IActionFilter{/// <summary>/// 监控日志/// </summary>public static ILogger LoggerMonitor { get; set; }/// <summary>/// 错误日志/// </summary>public static ILogger LoggerError { get; set; }private Stopwatch _stopwatch;/// <summary>/// 创建请求日志文本/// </summary>/// <param name="method"></param>/// <param name="controllerName"></param>/// <param name="actionName"></param>/// <param name="actionArgs"></param>/// <returns></returns>private static string CreateRequestLogText(string method, string controllerName, string actionName, string requestHead, string requestBody){StringBuilder sb = new StringBuilder();sb.Append($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 请求{method}/{controllerName}/{actionName}接口,请求Head:{requestHead}\n");sb.Append($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 请求{method}/{controllerName}/{actionName}接口,请求Body:{requestBody}\n");return sb.ToString();}	/// <summary>/// 创建响应日志文本/// </summary>/// <param name="method"></param>/// <param name="controllerName"></param>/// <param name="actionName"></param>/// <param name="result"></param>/// <returns></returns>private static string CreateResponseLogText(string method, string controllerName, string actionName, object result){StringBuilder sb = new StringBuilder();sb.Append($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 完成请求{method}/{controllerName}/{actionName}接口,返回结果:");if (result != null){sb.Append($"{JsonConvert.SerializeObject(result)}");}else{sb.Append($"无");}return sb.ToString();}/// <summary>/// 方法执行前,记录接口请求参数/// </summary>/// <param name="context"></param>/// <exception cref="NotImplementedException"></exception>public async void OnActionExecuting(ActionExecutingContext context){ErrorLog.Write("==================================================================================================================================");_stopwatch = new Stopwatch();_stopwatch.Start();//throw new NotImplementedException();if (LoggerMonitor != null){//记录请求参数日志ControllerActionDescriptor desc = context.ActionDescriptor as ControllerActionDescriptor;if (desc != null){Dictionary<string, object> headers = new Dictionary<string, object>();var requestHeaders = context.HttpContext.Request.Headers;// 访问请求中的 header 信息foreach (var header in requestHeaders){headers.Add(header.Key, header.Value);}var requestHead = JsonConvert.SerializeObject(headers);Dictionary<string, object> bodys = new Dictionary<string, object>();var actionArguments = context.ActionArguments;// 访问请求中的参数foreach (var argument in actionArguments){//dic.Add(argument.Key, argument.Value);var parameter = JsonConvert.DeserializeObject<Dictionary<string, object>>(argument.Value.ToString());foreach (var item in parameter){bodys.Add(item.Key, item.Value);}}var requestBody = JsonConvert.SerializeObject(bodys);var logText = CreateRequestLogText(context.HttpContext.Request.Method, desc.ControllerName, desc.ActionName, requestHead, requestBody);LoggerMonitor.LogDebug(logText);ErrorLog.Write(logText);}}}//方法执行后,记录接口请求结果public void OnActionExecuted(ActionExecutedContext context){//throw new NotImplementedException();_stopwatch.Stop();long elaspsedMillisedconds = _stopwatch.ElapsedMilliseconds;string msg = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 接口执行时间:{elaspsedMillisedconds}毫秒";//ErrorLog.Write(msg);if (context.Exception != null){// 记录异常日志if (LoggerError != null){LoggerError.LogError(context.Exception, context.Exception.Message);ErrorLog.Write($@"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 接口异常:{JsonConvert.SerializeObject(context.Exception)}");ErrorLog.Write($@"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")} 异常提示信息:{JsonConvert.SerializeObject(context.Exception.Message)}");}}if (LoggerMonitor != null){// 记录请求结果日志ControllerActionDescriptor desc = context.ActionDescriptor as ControllerActionDescriptor;if (desc != null){ObjectResult rst = context.Result as ObjectResult;object rstValue = rst != null ? rst.Value : null;var logText = CreateResponseLogText(context.HttpContext.Request.Method,desc.ControllerName,desc.ActionName,rstValue);LoggerMonitor.LogDebug(logText);ErrorLog.Write(logText);}}ErrorLog.Write(msg);ErrorLog.Write("==================================================================================================================================");}}
}

五.在 Program 中配置行动过滤器 ActionFilter

在这里插入图片描述

using Microsoft.AspNetCore.Mvc.Filters;
using WebApiTest.Filter;var builder = WebApplication.CreateBuilder(args);var configuration = builder.Configuration;
// Add services to the container.builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();#region 接口行动过滤器
// Add services to the container.
builder.Services.AddSingleton<IActionFilter>(new ActionFilter()); // 初始化 LoggerMonitor
builder.Services.AddSingleton<IActionFilter>(new ActionFilter()); // 初始化 LoggerError
builder.Services.AddScoped<ActionFilter>(); // 注册 ActionFilterbuilder.Services.AddControllers(options => {options.Filters.Add(new ActionFilter());
});var serviceProvider = builder.Services.BuildServiceProvider();
ActionFilter.LoggerError = serviceProvider.GetRequiredService<ILogger<ActionFilter>>();
ActionFilter.LoggerMonitor = serviceProvider.GetRequiredService<ILogger<ActionFilter>>();
#endregionvar app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseAuthorization();app.MapControllers();app.Run();

六.创建一个接口,调试执行一下

在这里插入图片描述

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;namespace WebApiTest.Controllers
{[ApiController][Route("Home")]public class HomeController : ControllerBase{[HttpGet][Route("Index")]public string Index(){return JsonConvert.SerializeObject(new { code = 0,data=true,msg="成功"});}}
}

在这里插入图片描述

接口请求成功,接着我们查看appsettings.json中配置的路径文件中,日志的记录情况

在这里插入图片描述

结果

.NetCore6.0项目,ActionFilter行动过滤器搭建成功,之后这个框架的接口请求就都会携带日志了

相关文章:

.NetCore6.0实现ActionFilter过滤器记录接口请求日志

文章目录 目的实现案例&#xff1a;一.首先我们新建一个WebApi项目二.配置 appsettings.json 文件&#xff0c;配置日志存放路径三.创建 Model 文件夹&#xff0c;创建AppConfig类和ErrorLog类1.在AppConfig类中编写一个GetConfigInfo方法获取配置文件中的值2.在ErrorLog类中&a…...

代码详解:2024美团春招实习笔试第一场0309,是难还是简单?

前言: 1.第一题&#xff08;模拟&#xff09; 2.第二题&#xff08;模拟&#xff09; 3.第三题&#xff08;二维前缀和&#xff09; 4.第四题的思维&#xff08;双指针&#xff09; 5.第五题难度比较大&#xff08;并查集删边离散化&#xff09; 一.小美的MT MT 是美团的…...

平衡二叉树

前言 在关键字排列随机的情况下&#xff0c;二叉排序树的平均查找长度和 l o g n log n logn是等数量级的。在某些情况下&#xff0c;尚需在构成二叉排序树的过程中进行“平衡化”处理&#xff0c;使其成为平衡二叉树。 如果任何初始化序列构成的二叉排序树都是平衡二叉树&…...

脚本自动化 设置快捷方式并设置为管理员运行

自动化创建快捷方式并设置为始终以管理员权限运行&#xff0c;可以通过编写批处理脚本来实现。以下是一个创建.bat批处理文件快捷方式并设置为管理员运行的示例脚本&#xff1a; batch echo off set SCRIPT_PATH"C:\Scripts\myScript.bat" set SHORTCUT_PATH"%…...

TypeScript学习笔记(上):TypeScript的介绍、安装及常用类型

我对TypeScript的理解就是&#xff0c;TypeScript是增加了类型校验的JavaScript&#xff0c;能够把运行期错误提升至编译期 目录 TypeScript是什么&#xff1f; 安装编译 TS 的工具包 运行 TS 的步骤 TypeScript 常用类型 JS 已有类型 TS 新增类型 简单数据类型 数组类…...

Vue3学习记录(六)--- 组合式API之依赖注入和异步组件

一、依赖注入 1、简介 ​ 在前面的笔记中&#xff0c;我们学习过父组件向子组件传递数据时&#xff0c;需要借助props来实现。但如果父组件想要向孙子组件传递数据&#xff0c;那就要连续使用两层props逐级向下传递&#xff0c;如果要接收数据的是更深层的后代组件&#xff0…...

JZ76 删除链表中重复的结点

/*public class ListNode {int val;ListNode next null;ListNode(int val) {this.val val;} } */import java.util.*; public class Solution {public ListNode deleteDuplication(ListNode pHead) {//初步想想法&#xff1a; 弄一个hashmap 然后进行key存储起来。然后 如果存…...

20.2 nginx

20.2 nginx 1. 学习目标2. 介绍2.1 正向代理2.2 反向代理2.3 动态静态资源分离2.4 nginx优缺点3. 安装3.1 Linux安装****************************************************************************************************************************************************…...

MySQL学习Day26——事务基础知识

一、数据库事务概述: 事务是数据库区别于文件系统的重要特性之一,事务会让数据始终保持一致性,能通过事务机制恢复到某个时间点,可以保证提交到数据库的修改不会因为系统崩溃而丢失 1.查看引擎支持事务的情况:只有InnoDB存储引擎支持事务 SHOW ENGINES; 2.基本概念: 事…...

three.js 射线Ray,三维空间中绘制线框

效果&#xff1a; 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs"></div> <div>{{ res1 }}</div> <div>{{ res2 }}</div><…...

【Demo】游戏小地图

简介 该Demo基于2D关卡随机生成项目进行实现&#xff0c;旨在初步探索游戏小地图的制作。 演示 MiniMapDemo 资源下载 百度网盘&#xff08;提取码&#xff1a;1314&#xff09; 如果这篇文章对你有帮助&#xff0c;请给作者点个赞吧&#xff01;...

代码随想录算法训练营Day39 || leetCode 762.不同路径 || 63. 不同路径 II

62.不同路径 每一位的结果等于上方与左侧结果和 class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m,vector(n,0));for (int i 0; i < m; i) dp[i][0] 1;for (int j 0; j < n; j) dp[0][j] 1;for (int i 1; i < m; …...

Qt中parent()函数的使用

情景(需求)抽象&#xff1a; A类对象是B类对象的成员变量。 B类对象是A类对象的父亲。 A类对象中包含按钮&#xff0c;点击按钮&#xff0c;调用B类的成员函数。 示例&#xff1a; A类&#xff1a; #pragma once#include <QWidget> #include "ui_QtWidgetsCla…...

Python基础学习(5)流程控制

文章目录 一. 程序三大执行流程二. 分支结构1.单分支结构(if)2.双分支结构(if..else)3.多分支结构(if..elif..else) 二,缩进(tab键)三,循环结构1.while循环2.for循环①遍历字典 五.break&#xff0c;continue和pass语句1.break&#xff0c;continue2.pass Python基础学习(1)基本…...

代码随想录刷题笔记 DAY 42 | 最后一块石头的重量 II No.1049 | 目标和 No.494 | 一和零 No.474

文章目录 Day 4301. 最后一块石头的重量 II&#xff08;No. 1049&#xff09;<1> 题目<2> 笔记<3> 代码 02. 目标和&#xff08;No. 494&#xff09;<1> 题目<2> 笔记<3> 代码 03. 一和零&#xff08;No. 474&#xff09;<1> 题目&l…...

793.高精度乘法(acwing)

文章目录 793.高精度乘法题目描述高精度乘法 793.高精度乘法 题目描述 给定两个正整数A和B&#xff0c;请你计算A * B的值。 输入格式 共两行&#xff0c;第一行包含整数A&#xff0c;第二行包含整数B。 输出格式 共一行&#xff0c;包含A * B的值。 数据范围 1≤A的长度≤…...

考研经验|如何从考研失败中走出来?

对我来说&#xff0c;太丢人了 其实我在本科的时候在同学眼中&#xff0c;一直很优秀&#xff0c;每年奖学金必有我的&#xff0c;国家励志奖学金&#xff0c;国家奖学金&#xff0c;这种非常难拿的奖学金&#xff0c;我也拿过&#xff0c;本科期间学校有一个公费去新西兰留学的…...

SpringBoot如何修改pom依赖的默认版本号

1、找到SpringBoot父工程依赖。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version> </parent>2、ctrl 鼠标左键点击<artifact…...

UDP与TCP:了解这两种网络协议的不同之处

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

String、StringBuffer基本用法

一、StringBuffer基本用法 1.append():字符串连接操作 StringBuffer sb new StringBuffer();sb.append("a");sb.append("b");sb.append("c");sb.append("哈哈").append("d");System.out.println(sb);2.insert():在任意位…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

ubuntu中安装conda的后遗症

缘由: 在编译rk3588的sdk时&#xff0c;遇到编译buildroot失败&#xff0c;提示如下&#xff1a; 提示缺失expect&#xff0c;但是实测相关工具是在的&#xff0c;如下显示&#xff1a; 然后查找借助各个ai工具&#xff0c;重新安装相关的工具&#xff0c;依然无解。 解决&am…...

算法250609 高精度

加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统

核心速览 研究背景 ​​研究问题​​&#xff1a;这篇文章要解决的问题是当前大型语言模型&#xff08;LLMs&#xff09;在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色&#xff0c;但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成&#xff08;RA…...