ASP.NET Core 異常處理與日誌記錄

1.1. 異常處理

1.1.1. 異常產生的緣由及處理

異常是在編程時,一個意外的事件,如無效的輸入或鏈接丟失,當程序執行破壞的指令流時就會出現這種狀況。Exception是Exceptional event的簡要表達。異常的實現須要保存拋出異常捕獲點的必要信息,這會必定程度上致使程序變慢,這也是人們詬病異常性能的緣由。html

異常(Exception)是一種非程序緣由的操做失敗,而錯誤(Error)則意味着程序有缺陷。
Exception是一種類.例外會中斷執行堆棧直到被捕獲.一個異常能夠用來傳達一個錯誤,可是更廣泛的是用來表示出現了一些例外.數據庫

1.1.2. ASP.NET Core中啓動開發人員異常頁面

想要在應用程序中顯示詳細的異常信息,展現錯誤詳情的頁面在Microsoft.AspNetCore.Diagnostics包中,可是自從ASP.NET Core 2.0開始Microsoft.AspNetCore.All包裏面包含了全部以Microsoft.AspNetCore開頭的包,因此不須要在額外安裝Microsoft.AspNetCore.Diagnostics包,可是須要在Startup類的Configure方法中進行配置apache

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    
    env.EnvironmentName = EnvironmentName.Production;
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/error");
    }

UseDeveloperExceptionPage放在你想捕獲的中間件以前,如app.UseMvc編程

注:爲了應用程序的安全,通常不會在生產環境中啓起用開發者頁面(異常頁面)。json

示例安全

HomeController.cs 手動拋出一個異常app

public class HomeController : Controller
{
    public IActionResult Index()
    {
        throw new Exception("dddd");
        return View();
    }

}

運行結果框架

2017-11-07-21-57-08

這樣的錯誤提示是很難讓開發人員定位出錯的位置;若要展現開發者頁面,還須要將應用程序環境設置爲Developmentasp.net

2017-11-07-21-44-35

開發者頁面有幾個標籤頁面包含了異常信息和請求參數的信息:性能

2017-11-07-21-20-13

堆棧的詳細、查詢參數、Cookies信息和請求頭這些打印出來方便開發人員快速定位錯誤。可是程序在開發的時候能夠直接這樣定位出錯位置,可是在生產環境中就須要藉助日誌將出錯信息寫到日誌文件裏面以方便開發人員定位錯誤。

1.2. 日誌記錄

1.2.1. 日誌做用

程序中記錄日誌通常有兩個目的,故障定位和顯示程序運行狀態。好的日誌記錄方式能夠提供足夠多定位問題的依據。

1.2.2. 日誌等級

若是有良好的習慣的人平時工做的時候會將領導交待下來的工做分爲:緊急重要、重要不緊急、緊急不重要、不緊急不重要等;一樣ASP.NET Core也將日誌定義了多個等級,從0到5總共6個等級:

  • Trace = 0

這個級別只對開發人員調試有價值。這些消息可能包含敏感的應用程序數據,所以不該該在生產環境中啓用。

  • Debug = 1

對於在開發和調試過程當中具備短時間可用性的信息。若是不是出現問題在生產環境通常不建議啓用。

  • Information = 2

用於跟蹤應用程序,這些日誌有長期的價值。

  • Warning = 3

用於程序中的異常或意外事件。這些可能包括錯誤或其餘不致使應用程序中止的條件,可是可能須要進行排查。

  • Error = 4

對於不能處理的錯誤過異常。這些消息代表當前的活動或操做(例如當前的HTTP請求)失敗,而不是應用程序範圍的失敗。

  • Critical = 5

對於那些須要當即關注的失敗。示例:磁盤空間中的數據丟失場景。

開發人員能夠根據日誌級別將衆多日誌存儲到不到的介質中,以供分析用戶需求、定準程序錯誤等。

1.2.3. ASP.NET Core中的日誌接口

ASP.NET Core支持可與各類日誌記錄提供程序配合使用的日誌記錄API。 內置提供程序容許您將日誌發送到一個或多個目標,而且能夠插入第三方日誌記錄框架。

1.2.4. 實踐

用.NET Core內置日誌接口將日誌信息打印到控制檯上

public class Startup
{
    ...
    public virtual void Configure(IApplicationBuilder app)
    {
        ...
        app.UseExceptionHandler("/Home/Error");
        ...
    }
}
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    private readonly  ILogger _logger;
    public HomeController (ILogger<HomeController> logger) {
        _logger = logger;
    }

    public IActionResult Index () {
        throw new Exception ("dddd");
        return View ();
    }

    public IActionResult Error()
    {
        var feature = HttpContext.Features.Get<IExceptionHandlerFeature>();
        var error = feature?.Error;
        _logger.LogError("Oops!Error Info-----:", error);
        return View("~/Views/Shared/Error.cshtml", error);
    }
}

Program.cs

public class Program {
    public static void Main (string[] args) {
        BuildWebHost (args).Run ();
    }

    public static IWebHost BuildWebHost (string[] args) =>
        WebHost.CreateDefaultBuilder (args)
        .UseContentRoot (Directory.GetCurrentDirectory ())
        .ConfigureAppConfiguration ((hostingContext, config) => {
            var env = hostingContext.HostingEnvironment;
            config.AddJsonFile ("appsettings.json", optional : true, reloadOnChange : true)
                .AddJsonFile ($"appsettings.{env.EnvironmentName}.json", optional : true, reloadOnChange : true);
            config.AddEnvironmentVariables ();
        })
        .ConfigureLogging ((hostingContext, logging) => {
            logging.AddConfiguration (hostingContext.Configuration.GetSection ("Logging"));
            logging.AddConsole ();
            logging.AddDebug ();
        })
        .UseStartup<Startup> ()
        .Build ();
}

經過ASP.NET Core內置的日誌支持能夠很輕鬆將日誌打印到控制檯上面

2017-11-08-23-08-57

注:IExceptionHandlerFeature接口位於Microsoft.AspNetCore.Diagnostics包下,因此須要引入Microsoft.AspNetCore.DiagnosticsILogger接口定義在Microsoft.Extensions.Logging.Abstractions包,而且默認實如今Microsoft.Extensions.Logging包裏面。

可是,在生產環境中日誌是記錄在數據庫或文件當中,下面以log4net做爲例子將日誌記錄到文件當中。

log4net 保存日誌

在選擇log4net的時候最好選擇最新版,log4net從2.0.6開始支持.NET Core。

  • 安裝log4net

2017-11-13-20-44-02

執行dotnet restore 命令將nuget包拉到本地。肯定本地.nuget文件夾裏面有log4net而且版本號也一致。

2017-11-13-21-46-26

  • 配置log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- This section contains the log4net configuration settings -->
  <log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" />
    </appender>
    
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <param name="Encoding" value="utf-8" />
      <file value="log-file.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>

    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="Encoding" value="utf-8" />
      <file value="logfile/" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <staticLogFileName value="false" />
      <datePattern value="yyyyMMdd'.log'" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="1MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>

    <!-- Setup the root category, add the appenders and set the default level -->
    <root>
      <level value="ALL" />
      <appender-ref ref="ConsoleAppender" />
      <appender-ref ref="FileAppender" />
      <appender-ref ref="RollingLogFileAppender" />
    </root>

  </log4net>
</configuration>

這裏定義了三個appender,都會起做用;日誌等級爲ALL將會記錄全部類型的日誌。

Startup.cs

using System.IO;
using log4net;
using log4net.Config;
using log4net.Repository;


public class Startup
{
    public static  ILoggerRepository  Repository;
    public Startup (IHostingEnvironment env) {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
        Repository = LogManager.CreateRepository ("NETCoreRepository");
        XmlConfigurator.Configure (Repository, new FileInfo ("log4net.config"));
    }

HomeController.cs

public class HomeController : Controller {
        private ILog log = LogManager.GetLogger (Startup.Repository.Name, typeof (HomeController));
        
        public IActionResult Index () {
            throw new Exception ("Manul Exception:");
            return View ();
        }

        public IActionResult Error () {
            var feature = HttpContext.Features.Get<IExceptionHandlerFeature> ();
            var error = feature?.Error;
            log.Error(error);
            return View ("~/Views/Shared/Error.cshtml", error);
        }
    }

運行結果

訪問首頁時會出異常,根據跳轉到錯誤路由Error方法中;同時在項目中會生成兩個文件:

  1. FileAppender生成的log-file.log日誌文件

  2. RollingLogFileAppender 是按時間生成的日誌文件

2017-11-14-11-37-23

控件臺打印出來的日誌文件

2017-11-14-11-45-51

RollingLogFileAppender 打印的日誌文件

2017-11-14-11-46-53

FileAppender打段日誌文件

2017-11-14-11-47-21

從上面來看三種Appender打印的三種日誌是一致的,因此在實際開發的時候能夠根據須要來用哪一種方式進行記錄日誌。

1.3. 總結

本節講解了兩個知識點:

  • 異常產生及異常和錯誤的區別,在ASP.NET Core中捕獲異常,啓動開發者異常頁面。
  • ASP.NET Core內置日誌接口和使用log4net將異常日誌輸出到文件中

參與資料:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?tabs=aspnetcore2x

http://logging.apache.org/log4net/release/manual/configuration.html

做者:xdpie 出處: http://www.cnblogs.com/vipyoumay/p/7838069.html

相關文章
相關標籤/搜索