asp.net core添加全局異常處理及log4net、Nlog應用

0、目錄


 總體架構目錄:ASP.NET Core分佈式項目實戰-目錄html

1、介紹


 

此篇文章將會介紹項目的全局異常收集以及採用log4net或者NLog記錄。

衆所周知,一旦本身的項目報錯,若是沒有進行處理都是顯示不友好的,有得甚至直接爆出錯誤頁面,看的也是很奇怪。web

 爲了不出現這樣的錯誤以及在錯誤出現的時候能夠進行收集錯誤,供維護人員進行bug修改,所以須要進行全局異常的收集。json

 讓咱們開始部署吧。api

 

此篇文章的目錄微信

一、log4net使用架構

二、Nlog使用app

後期將會把NLog+ELK進行結合部署收集咱們的asp.net core的項目。你們能夠拭目以待吧。asp.net

 

2、部署(log4net使用)


 

一、新建一個asp.net core webapi的項目

而後目前我先引入 log4net   nuget包。分佈式

二、而後建立一個log4net.config文件

此文件中,我建立了一個是記錄 錯誤的文件夾(LogError)以及是記錄操做的文件夾(LogInfo),代碼以下:我把須要記錄的文件放在了log文件夾下面。佈局

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <log4net>
    <!-- 錯誤日誌類-->
    <logger name="logerror">
      <level value="ALL" />
      <appender-ref ref="ErrorAppender" />
    </logger>
    <!-- 錯誤日誌附加介質-->
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
      <!--日誌文件路徑-->
      <param name="File" value="Log\\LogError\\" />
      <!--是不是向文件中追加日誌-->
      <param name="AppendToFile" value="true" />
      <!--log保留天數-->
      <param name="MaxSizeRollBackups" value="1000" />
      <!--最大文件大小-->
      <param name="MaxFileSize" value="10240" />
      <!--日誌文件名是不是固定不變的-->
      <param name="StaticLogFileName" value="false" />
      <!--日誌文件名格式爲:2008-08-31.log-->
      <param name="DatePattern" value="yyyy-MM-dd&quot;.htm&quot;" />
      <!--日誌根據日期滾動-->
      <param name="RollingStyle" value="Date" />
      <!--信息日誌佈局-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="&lt;HR COLOR=red&gt;%n【異常時間】:%d [%t] &lt;BR&gt;%n【異常級別】:%-5p &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
      </layout>
    </appender>

    <!-- 信息日誌類 -->
    <logger name="loginfo">
      <level value="ALL" />
      <appender-ref ref="InfoAppender" />
    </logger>
    <!-- 信息日誌附加介質-->
    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
      <!--日誌文件路徑-->
      <param name="File" value="Log\\LogInfo\\" />
      <!--是不是向文件中追加日誌-->
      <param name="AppendToFile" value="true" />
      <!--log保留天數-->
      <param name="MaxSizeRollBackups" value="100" />
      <param name="MaxFileSize" value="1" />
      <!--日誌文件名是不是固定不變的-->
      <param name="StaticLogFileName" value="false" />
      <!--日誌文件名格式爲:2008-08-31.log-->
      <param name="DatePattern" value="yyyy-MM-dd&quot;.htm&quot;" />
      <!--日誌根據日期滾動-->
      <param name="RollingStyle" value="Date" />
      <!--信息日誌佈局-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="&lt;HR COLOR=blue&gt;%n日誌時間:%d [%t] &lt;BR&gt;%n日誌級別:%-5p &lt;BR&gt;%n%m &lt;BR&gt;%n &lt;HR Size=1&gt;"  />
      </layout>
    </appender>
  </log4net>


  <!-- To customize the asp.net core module uncomment and edit the following section. 
  For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
  <!--
  <system.webServer>
    <handlers>
      <remove name="aspNetCore"/>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
  </system.webServer>
  -->

</configuration>

 

三、在asp.net core項目中 Startup.cs 中須要添加初始化log4net的倉儲名,主要是用來給log4net標記一個名稱,這邊能夠隨意。

 

四、在項目中建立一個類用來記錄log的日誌格式以及數據分類存放

建立LogHelper.cs,

 

定義log格式,固然本身能夠隨意定義哈。

#region 全局異常錯誤記錄持久化
        /// <summary>
        /// 全局異常錯誤記錄持久化
        /// </summary>
        /// <param name="throwMsg"></param>
        /// <param name="ex"></param>
        public static void ErrorLog(string throwMsg, Exception ex)
        {
            string errorMsg = string.Format("【拋出信息】:{0} <br>【異常類型】:{1} <br>【異常信息】:{2} <br>【堆棧調用】:{3}", new object[] { throwMsg,
                ex.GetType().Name, ex.Message, ex.StackTrace });
            errorMsg = errorMsg.Replace("\r\n", "<br>");
            errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>");
            logerror.Error(errorMsg);
        }
        #endregion
#region 自定義操做記錄
        /// <summary>
        /// 自定義操做記錄,與倉儲中的增刪改的日誌是記錄同一張表
        /// </summary>
        /// <param name="throwMsg"></param>
        /// <param name="ex"></param>
        public static void WriteLog(string throwMsg, Exception ex)
        {
            string errorMsg = string.Format("【拋出信息】:{0} <br>【異常類型】:{1} <br>【異常信息】:{2} <br>【堆棧調用】:{3}", new object[] { throwMsg,
                ex.GetType().Name, ex.Message, ex.StackTrace });
            errorMsg = errorMsg.Replace("\r\n", "<br>");
            errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>");
            logerror.Error(errorMsg);
        }
        #endregion

 

 

 五、有了以上的log格式,這樣我就開始定義一下全局異常處理吧

我這邊先建立一個全局異常處理類 GlobalExceptions.cs 而後須要在startup.cs中注入

在ConfigureServices 方法中注入。

//注入全局異常捕獲
services.AddMvc(o =>
{
o.Filters.Add(typeof(GlobalExceptions));
});

 

 

六、GlobalExceptions類中添加處理,固然異常須要繼承IExceptionFilter。

代碼以下:

GlobalExceptions 
public class GlobalExceptions : IExceptionFilter
    {
        private readonly IHostingEnvironment _env;
        public GlobalExceptions(IHostingEnvironment env)
        {
            _env = env;
        }
        public void OnException(ExceptionContext context)
        {
            var json = new JsonErrorResponse();
            //這裏面是自定義的操做記錄日誌
            if (context.Exception.GetType() == typeof(UserOperationException))
            {
                json.Message = context.Exception.Message;
                if (_env.IsDevelopment())
                {
                    json.DevelopmentMessage = context.Exception.StackTrace;//堆棧信息
                }
                context.Result = new BadRequestObjectResult(json);//返回異常數據
            }
            else
            {
                json.Message = "發生了未知內部錯誤";
                if (_env.IsDevelopment())
                {
                    json.DevelopmentMessage = context.Exception.StackTrace;//堆棧信息
                }
                context.Result = new InternalServerErrorObjectResult(json);
            }

            //採用log4net 進行錯誤日誌記錄
            LogHelper.ErrorLog(json.Message, context.Exception);

        }
    }
    public class InternalServerErrorObjectResult : ObjectResult
    {
        public InternalServerErrorObjectResult(object value) : base(value)
        {
            StatusCode = StatusCodes.Status500InternalServerError;
        }
    }

 

JsonErrorResponse.cs 

public class JsonErrorResponse
    {
        /// <summary>
        /// 生產環境的消息
        /// </summary>
        public string Message { get; set; }
        /// <summary>
        /// 開發環境的消息
        /// </summary>
        public string DevelopmentMessage { get; set; }
    }

 

UserOperationException.cs

/// <summary>
    /// 操做日誌
    /// </summary>
    public class UserOperationException : Exception
    {
        public UserOperationException() { }
        public UserOperationException(string message) : base(message) { }
        public UserOperationException(string message, Exception innerException) : base(message, innerException) { }
    }

 

 自此,全局異常配置完成,而後咱們能夠測試一下,隨便寫一個除以0的代碼在日誌記錄中就會出現以下的展現:

哇,發現個人錯誤日誌的格式很是的清楚,固然這個跟個人作事態度以及性格有很大的關係的啦,畢竟樓主仍是很帥的。哈哈哈。

 

3、NLog使用


 

一、在項目中添加nlog的nuget包引入,「NLog.Web.AspNetCore」

二、建立nlog.config文件,你們會發現個人log格式跟上面的格式操做,並且個人分層層次也很清楚。哈哈.

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">
  <!-- the targets to write to -->
  <targets>
    <!-- 輸出到文件,這個文件記錄全部的日誌 -->
    <target xsi:type="File" name="allfile" fileName="Log\LogAll\${shortdate}.htm"
                layout="&lt;HR COLOR=red&gt;${longdate}&lt;BR&gt;${logger}&lt;BR&gt;${uppercase:${level}}&lt;BR&gt;${message} ${exception}&lt;HR Size=1&gt;" />

    <!-- 輸出到文件,這個文件記錄錯誤日誌 -->
    <target xsi:type="File" name="logError" fileName="Log\LogError\${shortdate}.htm"
            layout="&lt;HR COLOR=red&gt;【異常時間】:${date} &lt;BR&gt;【異常級別】:${level:uppercase=true} &lt;BR&gt;${message}&lt;HR Size=1&gt;" />

    <!-- 輸出到文件,這個文件記錄操做日誌 -->
    <target xsi:type="File" name="logInfo" fileName="Log\LogInfo\${shortdate}.htm"
                 layout="&lt;HR COLOR=red&gt;【操做時間】:${date} &lt;BR&gt;【操做級別】:${level:uppercase=true} &lt;BR&gt;${message}&lt;HR Size=1&gt;" />
  </targets>
  <!-- rules to map from logger name to target -->
  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />
    <logger name="*" minlevel="Error" writeTo="logError" />
    <logger name="*" minlevel="Info" writeTo="logInfo" />
    <logger name="Microsoft.*" maxLevel="Info" final="true" />
  </rules>
</nlog>

 

注:而後將此文件點擊右鍵,選擇屬性,把複製輸出目錄修改成「始終複製」,沒法不修改,則會沒法加載此文件。

 

三、在startup.cs中的  Configure方法注入

//ILoggerFactory loggerFactory
loggerFactory.AddNLog(); NLog.LogManager.LoadConfiguration("nlog.config"
); //填入上面建立的文件的名稱

 而後運行如下便可看到在bin/debug下面生成文件夾

 

四、建立NLogHelp.cs類

public class NLogHelp
    {
        public static Logger logger = LogManager.GetCurrentClassLogger();
        public static void ErrorLog(string throwMsg, Exception ex)
        {
            string errorMsg = string.Format("【異常信息】:{0} <br>【異常類型】:{1} <br>【堆棧調用】:{2}",
                new object[] { throwMsg, ex.GetType().Name, ex.StackTrace });
            errorMsg = errorMsg.Replace("\r\n", "<br>");
            errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>");
            logger.Error(errorMsg);
        }
        public static void InfoLog(string operateMsg)
        {
            string errorMsg = string.Format("【操做信息】:{0} <br>",
                new object[] { operateMsg });
            errorMsg = errorMsg.Replace("\r\n", "<br>");
            logger.Info(errorMsg);
        }
    }

 

五、在上面log4net中的GlobalExceptions類把

LogHelper.ErrorLog(json.Message, context.Exception)替換成以下:NLogHelp.ErrorLog(json.Message,context.Exception)便可。

運行測試以下:
【異常時間】:2018/09/03 14:41:36.786 
【異常級別】:ERROR 
【異常信息】:錯誤消息:Failed to create instance of type
at AspectCore.Injector.ServiceCallSiteResolver.ResolvePropertyInject(ServiceDefinition service)
【異常類型】:InvalidOperationException 
【堆棧調用】: at AspectCore.Injector.ServiceCallSiteResolver.ResolveTypeService(TypeServiceDefinition typeServiceDefinition)
at AspectCore.Injector.ServiceCallSiteResolver.ResolvePropertyInject(ServiceDefinition service)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at AspectCore.Injector.ServiceResolver.b

 

自此,完美搞定,等後期我將會介紹採用ELK+NLog進行數據採集及展現,請你們拭目以待吧。

 


 

asp.net Core 交流羣:787464275 歡迎加羣交流
若是您認爲這篇文章還不錯或者有所收穫,您能夠點擊右下角的【推薦】按鈕精神支持,由於這種支持是我繼續寫做,分享的最大動力!

做者:LouieGuo
聲明:原創博客請在轉載時保留原文連接或者在文章開頭加上本人博客地址,如發現錯誤,歡迎批評指正。凡是轉載於本人的文章,不能設置打賞功能,若有特殊需求請與本人聯繫!

微信公衆號:歡迎關注                                                 QQ技術交流羣: 歡迎加羣

                

相關文章
相關標籤/搜索