上篇咋們聊到NLog在Core中比較基礎的使用,這篇接着上篇,對NLog做下封裝和過濾器集成,然后全局使用
說道這里咋們想說說過濾器Filter,Filter其實
是延續ASP.NET MVC的產物,同樣保留了五種的Filter,分別是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。
本篇咋們就用NLog日志記錄結合Filter中的Exception Filter異常日志全局過濾器,記錄全局異常日志方便咋們排錯,進入主題:
1、首先咋們創建個單獨的項目,命名為Nlog.Framework,然后在類庫中添加一個Log文件夾,把所有Log相關的文件都放到該文件夾下,添加后的項目結構如下圖所示:
2、在Log文件下創建個LogMessage類,里面是要記錄的一些信息屬性字段,代碼如下:

using System; using System.Collections.Generic; using System.Text; namespace Nlog.Framework.Log { /// <summary> /// 日志消息 /// </summary> public class LogMessage { /// <summary> /// IP /// </summary> public string IpAddress { get; set; } /// <summary> /// 操作人 /// </summary> public string OperationName { get; set; } /// <summary> /// 操作時間 /// </summary> public DateTime OperationTime { get; set; } /// <summary> /// 日志信息 /// </summary> public string LogInfo { get; set; } /// <summary> /// 跟蹤信息 /// </summary> public string StackTrace { get; set; } } }
3、在Log文件下創建個格式化LogFormat類,用來格式化日志輸出內容(日志看起來沒那么凌亂),代碼如下:

using System; using System.Collections.Generic; using System.Text; namespace Nlog.Framework.Log { public class LogFormat { public static string ErrorFormat(LogMessage logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("\r\n"); strInfo.Append("1. 操作時間: " + logMessage.OperationTime + " \r\n"); strInfo.Append("2. 操作人: " + logMessage.OperationName + " \r\n"); strInfo.Append("3. Ip : " + logMessage.IpAddress + "\r\n"); strInfo.Append("4. 錯誤內容: " + logMessage.LogInfo + "\r\n"); strInfo.Append("5. 跟蹤: " + logMessage.StackTrace + "\r\n"); strInfo.Append("----------------------------------------------------------------END---------------------------------------------------------------\r\n"); return strInfo.ToString(); } } }
4、在Log文件下定義一個接口,代碼如下:

using System; using System.Collections.Generic; using System.Text; namespace Nlog.Framework.Log { public interface INLogHelper { void LogError(Exception ex); } }
5、在Log文件下定義接口的實現類,代碼如下:

using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using System; namespace Nlog.Framework.Log { public class NLogHelper : INLogHelper { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger<NLogHelper> _logger; public NLogHelper(IHttpContextAccessor httpContextAccessor, ILogger<NLogHelper> logger) { _httpContextAccessor = httpContextAccessor; _logger = logger; } public void LogError(Exception ex) { LogMessage logMessage = new LogMessage(); logMessage.IpAddress = _httpContextAccessor.HttpContext.Request.Host.Host; if (ex.InnerException != null) logMessage.LogInfo = ex.InnerException.Message; else logMessage.LogInfo = ex.Message; logMessage.StackTrace = ex.StackTrace; logMessage.OperationTime = DateTime.Now; logMessage.OperationName = "administator"; _logger.LogError(LogFormat.ErrorFormat(logMessage)); } } }
6、添加個Filter文件夾,在當前文件夾下創建個全局異常過濾器,代碼如下:

using Microsoft.AspNetCore.Mvc.Filters; using Nlog.Framework.Log; using System; using System.Threading.Tasks; namespace FristCoreProgram.Filter { public class CustomerGlobalExceptionFilterAsync : ActionFilterAttribute, IAsyncExceptionFilter { private readonly INLogHelper _logHelper; public CustomerGlobalExceptionFilterAsync(INLogHelper logHelper) { _logHelper = logHelper; } /// <summary> /// 重新OnExceptionAsync方法 /// </summary> /// <param name="context">異常信息</param> /// <returns></returns> public Task OnExceptionAsync(ExceptionContext context) { // 如果異常沒有被處理,則進行處理 if (!context.ExceptionHandled) { // 記錄錯誤信息 _logHelper.LogError(context.Exception); // 設置為true,表示異常已經被處理了,其它捕獲異常的地方就不會再處理了 context.ExceptionHandled = true; } return Task.CompletedTask; } } }
7、修改Program類文件,代碼如下:

public static void Main(string[] args) { //設置讀取指定位置的nlog.config文件 //NLogBuilder.ConfigureNLog("XmlConfig/nlog.config"); //CreateWebHostBuilder(args).Build().Run(); //讀取指定位置的NLog配置文件 var logger = NLogBuilder.ConfigureNLog("XmlConfig/nlog.config").GetCurrentClassLogger(); try { logger.Info("Init Main..."); CreateWebHostBuilder(args).Build().Run(); } catch (System.Exception ex) { logger.Error(ex, "Stopped program because of exception"); } finally { LogManager.Shutdown(); } } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() //配置使用Nlog .UseNLog();
8、在Startup類里面ConfigureServices注入全局異常過濾器,,代碼如下:

public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc(options => { #region NLog過濾器注冊 options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync)); #endregion }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<INLogHelper, NLogHelper>(); //services.AddControllers(); }
PS:需要注意的是,由於Core的版本不同,Startup注入過濾器時方式有所不同
本例是core2.2版本注入的方式是:
options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync));
而core3.1版本注入的方式是:
services.AddControllers(options => options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync)));
9、最后再controller模擬個異常測試過濾器,代碼如下:
最最最后,訪問模擬異常的Action,查看日志文件,如下:
以上完成,這里只是封裝了Error,如果是其他級別的日志,可以自己封裝,然后注入到Startup類中!