上一篇文章咱們介紹了關於日誌記錄用的是Log4net,確實也很挺強大,可是別忘了咱們.NET有專屬於咱們的日誌框架,那就是NLog,相對於Log4net而言,NLog能夠說也是一個很好的記錄日誌的框架,而且其中的異步日誌等都有很是大的改善,本文藉此用了最新的NLog來在Web APi中進行記錄日誌。框架
利用NLog記錄日誌一樣能夠實現如咱們上篇文章利用Log4net來實現的那樣,因此在這裏就很少說,下面咱們來說另一種方式,那就是利用.NET內置的跟蹤級別類來進行記錄日誌。從而達到咱們所需。異步
在NLog.config配置文件中,咱們添加以下進行日誌的記錄【注意:只是簡單的利用了NLog,它仍是比較強大,更多的詳細內容請到官網或經過其餘途徑進行學習】ide
<targets> <target name="logfile" xsi:type="File" fileName="${basedir}/WebAPiNLog/${date:format=yyyyMMdd}.log" /> //在根目錄下的WebAPiNlog文件下生成日誌 </targets> <rules> <logger name="*" minlevel="Trace" writeTo="logfile" /> </rules>
既然是利用.NET內置的跟蹤級別類來實現,那麼咱們就須要實現其接口 ITraceWriter ,該接口須要實現以下方法學習
// 摘要: // 當且僅當在給定 category 和 level 容許跟蹤時,調用指定的 traceAction 以容許在新的 System.Web.Http.Tracing.TraceRecord // 中設置值。 // // 參數: // request: // 當前 System.Net.Http.HttpRequestMessage。它能夠爲 null,但這樣作將阻止後續跟蹤分析將跟蹤與特定請求關聯。 // // category: // 跟蹤的邏輯類別。用戶能夠定義本身的跟蹤。 // // level: // 寫入此跟蹤時所在的 System.Web.Http.Tracing.TraceLevel。 // // traceAction: // 啓用了跟蹤時要調用的操做。在此操做中,調用方應填充給定 System.Web.Http.Tracing.TraceRecord 的各個字段。 void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction);
【注意】利用內置的跟蹤級別則須要引用以下命名空間測試
using System.Web.Http.Tracing;
首先建立一個NLogger類並實現如上接口,固然咱們也得建立NLog實例並利用其實例進行級別處理,以下:ui
private static readonly Logger NlogLogger = LogManager.GetCurrentClassLogger();
接着咱們該如何作呢?咱們須要利用 TraceLevel 跟蹤級別,同時結合NLog獲得相應的級別信息,可能建立對象實例的過程比較長,咱們能夠利用Lazy<>來實現延遲加載,代碼以下:spa
private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>> (() => new Dictionary<TraceLevel, Action<string>> {{ TraceLevel.Info, NlogLogger.Info }, { TraceLevel.Debug, NlogLogger.Debug }, { TraceLevel.Error, NlogLogger.Error }, { TraceLevel.Fatal, NlogLogger.Fatal }, { TraceLevel.Warn, NlogLogger.Warn } });
而後,咱們定義一個屬性來返回其實例的值,以下日誌
private Dictionary<TraceLevel, Action<string>> Logger { get { return LoggingMap.Value; } }
緊接着咱們就是實現上述ITraceWriter接口code
public void Trace(System.Net.Http.HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction) { if (level != TraceLevel.Off) //若是沒用禁用日誌跟蹤 { if (traceAction != null && traceAction.Target != null) { category = category + Environment.NewLine + "Action Parameters : " + JsonConvert.SerializeObject(traceAction.Target); } var record = new TraceRecord(request, category, level); if (traceAction != null) traceAction(record); Log(record); } }
咱們記錄請求的參數,URL,以及Token、返回的JSON等等,上述Log方法則以下orm
private void Log(TraceRecord record) { var message = new StringBuilder(); if (!string.IsNullOrWhiteSpace(record.Message)) message.Append("").Append(record.Message + Environment.NewLine); if (record.Request != null) { if (record.Request.Method != null) message.Append("Method: " + record.Request.Method + Environment.NewLine); if (record.Request.RequestUri != null) message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine); if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null) message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine); } if (!string.IsNullOrWhiteSpace(record.Category)) message.Append("").Append(record.Category); if (!string.IsNullOrWhiteSpace(record.Operator)) message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation); }
咱們自定義日誌特性取名爲 NLogFilterAttribute ,咱們在訪問Action時來進行記載日誌也就是須要繼承於 ActionFilterAttribute ,簡單來講代碼以下:
public class NLogFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext filterContext) {......} }
那麼問題來了,.NET默認確確實實是走得內置的跟蹤級別,咱們如何讓其實現咱們上述實現的接口的級別呢?
此時咱們以前所學就派上了一點用場,咱們將其服務容器的關於ITraceWriter接口實現進行替換咱們自定義實現的接口便可,用以下一句便可
GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper());
接下來就是從服務容器中獲取咱們自定義實現的跟蹤級別
var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
而後調用好比說隔離級別中的Info,獲取其訪問的控制器名、Action名稱以及JSON等數據,以下:
trace.Info(filterContext.Request, "Controller : " + filterContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + filterContext.ActionDescriptor.ActionName, "JSON", filterContext.ActionArguments);
咱們簡單個給出所請求的控制器以及須要返回的數據,以下:
public class AboutController : ApiController { [POST("about")] public string about() { var test = new { name = "xpy0928", gender = "男", age = 12 }; return Newtonsoft.Json.JsonConvert.SerializeObject(test); } }
接下來咱們利用WebAPiTestOnHelpPage進行測試,看結果是否如咱們所指望
結果如咱們所期待的那樣
可是咱們的重點是是否生成了相應的日誌,咱們一塊兒來看下:
到此,關於利用.NET內置的跟蹤級別結合NLog來實現日誌的記錄也就告一段落,接下來咱們來看看異常處理
既然異常處理,那麼咱們固然就得利用自定義異常特性實現 ExceptionFilterAttribute ,其基本實現以下:
public class CustomExceptionAttribute:ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) {....} }
關於其實現和上面大同小異,以下
GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper()); var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter(); trace.Error(actionExecutedContext.Request, "Controller : " + actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + actionExecutedContext.ActionContext.ActionDescriptor.ActionName, actionExecutedContext.Exception); var exceptionType = actionExecutedContext.Exception.GetType(); if (exceptionType == typeof(ValidationException)) { var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(actionExecutedContext.Exception.Message), ReasonPhrase = "ValidationException", }; throw new HttpResponseException(resp); } else if (exceptionType == typeof(UnauthorizedAccessException)) { throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.Unauthorized)); } else { throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError)); }
此時咱們還須要在日誌NLogger類中添加以下一句
//處理異常 if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message)) { var exceptionType = record.Exception.GetType(); message.Append(Environment.NewLine); message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine); }
如此就基本實現了利用NLog記錄異常,固然咱們能夠自定義個異常類來更好的管理異常例如,以下:
public class ApiExceptions:Exception { int ErrorCode { get; set; } string ErrorDescription { get; set; } HttpStatusCode HttpStatus { get; set; } }
本節咱們學習了利用NLog來實現記錄異常經過集合內置的跟蹤級別。NLog是屬於.NET因此就單獨拿來說講,其強大也是不可言喻的。