文章目录
- 目的
- 实现案例:
-
- 一.首先我们新建一个WebApi项目
- [二.配置 appsettings.json 文件,配置日志存放路径](#二.配置 appsettings.json 文件,配置日志存放路径)
- [三.创建 Model 文件夹,创建AppConfig类和ErrorLog类](#三.创建 Model 文件夹,创建AppConfig类和ErrorLog类)
- 四.创建Filter文件夹,创建ActionFilter实现行动过滤器,实现记录接口日志
- [五.在 Program 中配置行动过滤器 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>(); // 注册 ActionFilter
builder.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>>();
#endregion
var 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行动过滤器搭建成功,之后这个框架的接口请求就都会携带日志了