巧用ActionFilterAttribute實(shí)現(xiàn)API日志的記錄
本文轉(zhuǎn)載自微信公眾號(hào)「UP技術(shù)控」,作者conan5566。轉(zhuǎn)載本文請(qǐng)聯(lián)系UP技術(shù)控公眾號(hào)。
背景
上回提到開發(fā)web api的時(shí)候,一般是需要記錄api的輸入輸出信息,方便后續(xù)排查問題;使用的是委托的形式進(jìn)行記錄日志。
使用Func
這次我們使用另外一種方式,F(xiàn)ilter來記錄輸入輸出日志。
實(shí)現(xiàn)方式
1、首先在進(jìn)入action的時(shí)候,定義OnActionExecuting。
- public override void OnActionExecuting(ActionExecutingContext context)
- {
- base.OnActionExecuting(context);
- // 后續(xù)添加了獲取請(qǐng)求的請(qǐng)求體,如果在實(shí)際項(xiàng)目中不需要?jiǎng)h除即可
- long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
- if (contentLen > 0)
- {
- // 讀取請(qǐng)求體中所有內(nèi)容
- 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);
- // 轉(zhuǎn)化為字符串
- RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
- }
- ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);
- Stopwatch = new Stopwatch();
- Stopwatch.Start();
- }
2、定義Stopwatch ,計(jì)算方法的耗時(shí)。
- private string ActionArguments { get; set; }
- /// <summary>
- /// 請(qǐng)求體中的所有值
- /// </summary>
- private string RequestBody { get; set; }
- private Stopwatch Stopwatch { get; set; }
3、結(jié)束的時(shí)候,把信息打印出來OnActionExecuted。
- 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 controller = context.Controller.ToString();
- string action = context.ActionDescriptor.DisplayName;
- string token = "";
- if (context.HttpContext.Request != null && context.HttpContext.Request.Headers != null && context.HttpContext.Request.Headers["Authorization"].Count > 0)
- {
- token = context.HttpContext.Request.Headers["Authorization"];
- }
- string qs = ActionArguments;
- dynamic result = context?.Result?.GetType()?.Name == "EmptyResult" ? new { Value = "無返回結(jié)果" } : context?.Result as dynamic;
- string res = "在返回結(jié)果前發(fā)生了異常";
- try
- {
- if (result != null)
- {
- res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
- }
- }
- catch (System.Exception)
- {
- res = "日志未獲取到結(jié)果,返回的數(shù)據(jù)無法序列化";
- }
- NLogger.Info(
- $"地址:{url} \n " +
- $"controller:{controller} \n " +
- $"action:{action} \n " +
- $"token:{token} \n " +
- $"方式:{method} \n " +
- $"請(qǐng)求體:{RequestBody} \n " +
- $"參數(shù):{qs}\n " +
- $"結(jié)果:{res}\n " +
- $"耗時(shí):{Stopwatch.Elapsed.TotalMilliseconds} 毫秒(指控制器內(nèi)對(duì)應(yīng)方法執(zhí)行完畢的時(shí)間)");
- }
4、控制器調(diào)用LogAttribute。
- /// <summary>
- ///
- /// </summary>
- [Produces("application/json")]
- [LogAttribute]
- [CustomExceptionFilterAttribute]
- public class DefaultController : Controller
- {
- }
完整代碼
- using CompanyName.ProjectName.Core;
- using Microsoft.AspNetCore.Mvc.Filters;
- using System.Diagnostics;
- namespace CompanyName.ProjectName.HttpApi.Host.Code
- {
- /// <summary>
- /// 攔截器
- /// </summary>
- public class LogAttribute : ActionFilterAttribute
- {
- private string ActionArguments { get; set; }
- /// <summary>
- /// 請(qǐng)求體中的所有值
- /// </summary>
- private string RequestBody { get; set; }
- private Stopwatch Stopwatch { get; set; }
- /// <summary>
- ///
- /// </summary>
- /// <param name="context"></param>
- public override void OnActionExecuting(ActionExecutingContext context)
- {
- base.OnActionExecuting(context);
- // 后續(xù)添加了獲取請(qǐng)求的請(qǐng)求體,如果在實(shí)際項(xiàng)目中不需要?jiǎng)h除即可
- long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
- if (contentLen > 0)
- {
- // 讀取請(qǐng)求體中所有內(nèi)容
- 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);
- // 轉(zhuǎn)化為字符串
- RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
- }
- ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);
- Stopwatch = new Stopwatch();
- Stopwatch.Start();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="context"></param>
- 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 controller = context.Controller.ToString();
- string action = context.ActionDescriptor.DisplayName;
- string token = "";
- if (context.HttpContext.Request != null && context.HttpContext.Request.Headers != null && context.HttpContext.Request.Headers["Authorization"].Count > 0)
- {
- token = context.HttpContext.Request.Headers["Authorization"];
- }
- string qs = ActionArguments;
- dynamic result = context?.Result?.GetType()?.Name == "EmptyResult" ? new { Value = "無返回結(jié)果" } : context?.Result as dynamic;
- string res = "在返回結(jié)果前發(fā)生了異常";
- try
- {
- if (result != null)
- {
- res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
- }
- }
- catch (System.Exception)
- {
- res = "日志未獲取到結(jié)果,返回的數(shù)據(jù)無法序列化";
- }
- NLogger.Info(
- $"地址:{url} \n " +
- $"controller:{controller} \n " +
- $"action:{action} \n " +
- $"token:{token} \n " +
- $"方式:{method} \n " +
- $"請(qǐng)求體:{RequestBody} \n " +
- $"參數(shù):{qs}\n " +
- $"結(jié)果:{res}\n " +
- $"耗時(shí):{Stopwatch.Elapsed.TotalMilliseconds} 毫秒(指控制器內(nèi)對(duì)應(yīng)方法執(zhí)行完畢的時(shí)間)");
- }
- }
- }