一、前言
当线上程序曝出问题,最先想到的是看一下日志,排查是什么问题。这样做的前提是有详尽的日志记录,不光记录异常还要记录请求的数据,比如请求地址、方式、参数、结果等等。文中记录了以过滤器特性的方式实现了方便的记录请求数据的日志输出。
二、实现
日志过滤器代码。
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc.Filters;
using wxApp.Code.Creater.Api.Common;
namespace wxApp.Code.Creater.Api.Filters
{
public class LogAttribute : ActionFilterAttribute
{
private string LogFlag { get; set; }
private string ActionArguments { get; set; }
///
/// 请求体中的所有值
///
private string RequestBody { get; set; }
private Stopwatch Stopwatch { get; set; }
public LogAttribute(string logFlag)
{
LogFlag = logFlag;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
// 后续添加了获取请求的请求体,如果在实际项目中不需要删除即可
long contentLen = context.HttpContext.Request.ContentLength==null?0:context.HttpContext.Request.ContentLength.Value;
if (contentLen > 0)
{
// 读取请求体中所有内容
System.IO.Stream stream = context.HttpContext.Request.Body;
if(context.HttpContext.Request.Method == "POST")
{
stream.Position = 0;
}
byte[] buffer = new byte[contentLen];
stream.Read(buffer, 0, buffer.Length);
// 转化为字符串
RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
}
ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);
Stopwatch = new Stopwatch();
Stopwatch.Start();
}
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
Stopwatch.Stop();
string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
string method = context.HttpContext.Request.Method;
string qs = ActionArguments;
dynamic result = context.Result.GetType().Name == "EmptyResult" ? new { Value = "无返回结果" } : context.Result as dynamic ;
string res = "在返回结果前发生了异常";
try
{
if(result != null)
{
res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
}
}
catch (System.Exception)
{
res = "日志未获取到结果,返回的数据无法序列化";
}
Logger.Log.Info($"\n 方法:{LogFlag} \n " +
$"地址:{url} \n " +
$"方式:{method} \n " +
$"请求体:{RequestBody} \n "+
$"参数:{qs}\n " +
$"结果:{res}\n " +
$"耗时:{Stopwatch.Elapsed.TotalMilliseconds} 毫秒(指控制器内对应方法执行完毕的时间)");
}
}
}
过滤器调用。
// GET
[HttpGet,Filters.Log("测试get")]
public IEnumerable Get(string p,string v)
{
return new string[] { "value", "value2" };
}