在ASP.NET MVC 3中使用日志記錄組件Elmah和NLog


    Elmah:主要針對Web應用程序,全局性地捕獲應用程序中未處理的異常。

    NLog:通用的日志記錄組件,與Log4Net屬於同類組件。相對於Elmah更通用,不局限於Web應用程序,還可以區分日志級別(詳見“使用NLog”一節),但是在錯誤日志記錄方面,需要花費比較多的工夫才能實現Elmah提供的功能。

    在ASP.NET MVC應用程序中可以考慮使用這Elmah+NLog進行互補,也可以使用NLog+HandleErrorAttribute實現所有日志的記錄。下面就說明一下如何使用Elmah和NLog。

使用Elmah

一、安裝與基本配置

1、使用Nuget安裝Elmah組件

ElMAH和ELMAH Core Library是必需的組件,如果沒有安裝ELMAH on MS SQL Sever組件,錯誤日志將被記錄在內存里,一旦應用程序重啟,日志就會丟失。這些組件安裝之后,會在Web.Config文件中添加一些默認的配置。

2、修改ELMAH的配置。

    1)修改ELMAH的數據庫連接。

1 <connectionStrings>    
2   <add name="elmah-sqlserver" connectionString="server=(local);Initial Catalog=PE.LayerArtitecture;Integrated Security=True;" providerName="System.Data.SqlClient" /> 
3 </connectionStrings> 

    2)啟用自定義錯誤頁。

    在<system.web>節點下添加:

<system.web> 
    <httpModules> 
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" /> 
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" /> 
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" /> 
    </httpModules> 
    <customErrors mode="On" defaultRedirect="GenericErrorPage.html" /> 
</system.web>
 說明: GenericErrorPage.html需要自己創建。

     3)創建數據表

CREATE TABLE [dbo].[ELMAH_Error]( 
    [ErrorId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_ELMAH_Error_ErrorId]  DEFAULT (newid()), 
    [Application] [nvarchar](60) NOT NULL, 
    [Host] [nvarchar](50) NOT NULL, 
    [Type] [nvarchar](100) NOT NULL, 
    [Source] [nvarchar](60) NOT NULL, 
    [Message] [nvarchar](500) NOT NULL, 
    [User] [nvarchar](50) NOT NULL, 
    [StatusCode] [int] NOT NULL, 
    [TimeUtc] [datetime] NOT NULL, 
    [Sequence] [int] IDENTITY(1,1) NOT NULL, 
    [AllXml] [ntext] NOT NULL, 
 CONSTRAINT [PK_ELMAH_Error] PRIMARY KEY NONCLUSTERED 
( 
    [ErrorId] ASC 
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 
至此,即完成了ELMAH的基本配置。

二、查看錯誤日志

1、在視圖上添加一個不存在的Action鏈接。

<table> 
    <thead> 
        <td>分類名稱</td> 
        <td>描述</td> 
    </thead> 
    @Html.ActionLink("Error Handle Sample", "Index1"); 
</table> 

2、點擊鏈接“Error Handle Sample”,正常情況下,會出現異常黃屏頁面,因為Index1這個Action並不存在。但是因為使用了Elmah進行全局異常控制,所以會跳轉到錯誤頁面,並將異常信息記錄到錯誤日志中(需要一定的配置,后面會介紹)。


3、查看錯誤日志

 

    1)點擊Details,可以看到報錯黃屏信息:


 

    2)還可以查看報錯時,服務器以及客戶端的信息:

三、禁止非授權用戶查看日志

在Web.Config中,去掉授權配置的注釋:

 

配置完之后,非“admin”角色的用戶就會被重定向到登錄頁。

四、替換掉ASP.NET自帶的HandleErrorAttribute過濾器

在Controller的某個Action中使用"Throw new Exception("出錯了!")"顯示地拋出一個異常,你會發現Elmah並不會記錄這個異常,這是因為ASP.NET MVC默認在Global.asax中全局注冊了HandleErrorAttribute過濾器,所以程序中出現的異常都會被其捕獲;但是,HandleErrorAttribute沒有日志記錄,所以使用Elmah替換HandleErrorAttribute也是一種常用的做法。實現步驟如下:

1、安裝Nuget組件Elmah.MVC

2、確保FilterConfig.cs或者Global.asax中沒有注冊HandleErrorAttribute(實際上Elmah.MVC組件已經注冊了,但是可以通過配置文件控制是否啟用該過濾器),也就是說,沒有下面這句代碼:

filters.Add(new HandleErrorAttribute()); 

3、按以下參數值配置Web.Config文件

<appSettings> 
  <add key="webpages:Version" value="2.0.0.0" /> 
  <add key="webpages:Enabled" value="false" /> 
  <add key="PreserveLoginUrl" value="true" /> 
  <add key="ClientValidationEnabled" value="true" /> 
  <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
  <add key="elmah.mvc.disableHandler" value="false" /> 
  <add key="elmah.mvc.disableHandleErrorFilter" value="true" /> 
  <add key="elmah.mvc.requiresAuthentication" value="false" /> 
  <add key="elmah.mvc.allowedRoles" value="*" /> 
  <add key="elmah.mvc.route" value="elmah" /> 
</appSettings> 

    elmah.mvc.disableHandleErrorFilter:是否“禁止使用HandleErrorAttribute”,這里應設置為true;

使用NLog

一、安裝NLog組件

通過NGet安裝以下三個包:

Nlog包含了日志記錄的主要功能,Nlog Configuration為你創建一個Nlog需要使用的空NLog.config文件,NLog Schema for intellisense(TM)在編輯NLog.config時提供智能提示。

二、日志組件API

在日志組件中用得最多的兩個類分別是NLog命名空間下的Logger和LoggerManager。Logger代表已經命名的日志來源,並且提供了發出日志信息的方法,而LoggerManager則提供了創建和管理Logger的實例。

    需要理解的一點是,Logger只代表日志源信息,而不關心日志的輸出位置。日志的輸出位置是通過配置文件或者配置API來設置的。

三、創建Logger實例

// 方法1: 
using NLog; 
Logger logger = LogManager.GetLogger("MyClassName"); 
                                         
// 方法2: 
namespace MyNamespace 
{ 
  public class MyClass 
  { 
    private static Logger logger = LogManager.GetCurrentClassLogger(); 
  } 
} 

四、日志級別

每條日志消息都有與之關聯的日志級別,用來表示該日志有多重要/詳細。NLog能夠基於Logger的名稱和級別來路由(也就是說,確定哪些的日志需要記錄到哪些位置)日志消息。

NLog支持以下的日志級別:

  • Trace - 很細節的信息。一般在開發環境中使用。

  • Debug -  調試信息, 用得比Trace少, 一般不會再產品環境中使用。

  • Info - 信息消息,一般在產品環境中啟用。 information messages, which are normally enabled in production environment

  • Warn - 警告消息, 一般用於非關鍵性的問題,可以恢復或者是臨時性的失敗。

  • Error - 錯誤消息

  • Fatal - 非常嚴重的錯誤

五、發出錯誤消息

using NLog; 
                                  
public class MyClass 
{ 
  private static Logger logger = LogManager.GetCurrentClassLogger(); 
                                  
  public void MyMethod1() 
  { 
    logger.Trace("Sample trace message"); 
    logger.Debug("Sample debug message"); 
    logger.Info("Sample informational message"); 
    logger.Warn("Sample warning message"); 
    logger.Error("Sample error message"); 
    logger.Fatal("Sample fatal error message"); 
                                  
    // alternatively you can call the Log() method 
    // and pass log level as the parameter. 
    logger.Log(LogLevel.Info, "Sample fatal error message"); 
  } 
} 

六、配置文件

logger.Trace()等等方法,只是在程序里發出日志消息,所以我們還需要在配置文件里設置哪些消息需要被記錄下來,以及記錄到什么位置(文本文件、數據庫,等等)。

1、在<targets>節點下,添加:

<target name="logfile" xsi:type="File" fileName="file.txt" /> 

代碼定義了一個目標位置,用於將日志發送到file.txt文件。

2、在<rules>節點下,添加:

<logger name="*" minlevel="Info" writeTo="logfile" /> 

這段代碼將會將所有(name="*")級別為Info或者更高(包含Info, Warn, Error, Fatal)的日志轉發到名為logfile的目標位置。

七、多個目標位置

<?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"> 
                           
    <targets> 
        <target name="logfile" xsi:type="File" fileName="file.txt" /> 
        <target name="console" xsi:type="Console" /> 
    </targets> 
                           
    <rules> 
        <logger name="*" minlevel="Trace" writeTo="logfile" /> 
        <logger name="*" minlevel="Info" writeTo="console" /> 
    </rules> 
</nlog> 

八、特定Logger的路由

可以在配置文件中指定只對某一個組件的日志進行記錄。

<?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"> 
                        
    <targets> 
        <target name="logfile" xsi:type="File" fileName="file.txt" /> 
    </targets> 
                        
    <rules> 
        <logger name="SomeNamespace.Component.*" minlevel="Trace" writeTo="logfile" final="true" /> 
        <logger name="*" minlevel="Info" writeTo="logfile" /> 
    </rules> 
</nlog>  

這段代碼表示只對以SomeNamespace.Component為前綴命名的組件的日志消息進行記錄,final=“true”,表示這是最后一條日志規則,后續規則不會生效。

九、包裝器

  • ImpersonatingWrapper - Impersonates another user for the duration of the write.

  • AsyncWrapper - 提供異步、緩沖執行日志寫入操作。 

  • FallbackGroup - 提供日志寫入出錯時的反饋。

  • FilteringWrapper - 基於條件過濾日志記錄。 Filters log entries based on a condition.

以異步操作為例:

<?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"> 
                   
    <targets> 
        <target name="asyncFile" xsi:type="AsyncWrapper"> 
            <target name="logfile" xsi:type="File" fileName="file.txt" /> 
        </target> 
    </targets> 
                   
    <rules> 
        <logger name="*" minlevel="Info" writeTo="asyncFile" /> 
    </rules> 
</nlog>  

十、布局

設置日志的輸出格式

<target name="logfile" xsi:type="File" fileName="file.txt" layout="${date:format=yyyyMMddHHmmss} ${message}" /> 

十一、在ASP.NET MVC 3中使用NLog記錄用戶操作

需求:使用日志記錄一個訪問的UserName、Controller、Action、時間戳。

1、增加名為UserTrackerLogAttribute的Filter

public class UserTrackerLogAttribute : ActionFilterAttribute, IActionFilter 
{        
private static Logger logger = LogManager.GetCurrentClassLogger();
public override void OnActionExecuted(ActionExecutedContext filterContext) { var actionDescriptor= filterContext.ActionDescriptor; string controllerName = actionDescriptor.ControllerDescriptor.ControllerName; string actionName = actionDescriptor.ActionName; string userName = filterContext.HttpContext.User.Identity.Name.ToString(); DateTime timeStamp = filterContext.HttpContext.Timestamp; string routeId=string.Empty; if (filterContext.RouteData.Values["id"] != null) { routeId = filterContext.RouteData.Values["id"].ToString(); } StringBuilder message = new StringBuilder(); message.Append("UserName="); message.Append(userName + "|"); message.Append("Controller="); message.Append(controllerName+"|"); message.Append("Action="); message.Append(actionName + "|"); message.Append("TimeStamp="); message.Append(timeStamp.ToString() + "|"); if (!string.IsNullOrEmpty(routeId)) { message.Append("RouteId="); message.Append(routeId); }

logger.Log(message.ToString()); base.OnActionExecuted(filterContext); } }  

2、在需要記錄操作的Action中標記自定義的Filter

[UserTrackerLog] 
public ActionResult Index() 
{ 
    return View(); 
}  

3、配置文件沿用上文target的name屬性值為“logfile”的配置。

4、使用Legit Log Viewer可視化查看~/Logs/下的日志文件。

十二、將日志記錄到Sql Server

1、創建數據表

CREATE TABLE [dbo].[NLog_Error]( 
  [Id] [int] IDENTITY(1,1) NOT NULL, 
  [time_stamp] [datetime] NOT NULL, 
  [host] [nvarchar](max) NOT NULL,  
  [type] [nvarchar](50) NOT NULL,  
  [source] [nvarchar](50) NOT NULL,  
  [message] [nvarchar](max) NOT NULL,  
  [level] [nvarchar](50) NOT NULL,  
  [logger] [nvarchar](50) NOT NULL,  
  [stacktrace] [nvarchar](max) NOT NULL,  
  [allxml] [ntext] NOT NULL,  
 CONSTRAINT [PK_NLogError] PRIMARY KEY CLUSTERED  
(  
    [Id] ASC 
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]  
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 
  GO  
ALTER TABLE [dbo].[NLog_Error] ADD  CONSTRAINT [DF_NLogError_time_stamp]  DEFAULT (getdate()) FOR [time_stamp] 
GO 

2、配置Nlog.Config

<targets>  
    <target xsi:type="Database" name="databaselog"> 
      <dbProvider>System.Data.SqlClient</dbProvider> 
      <connectionString>server=(local);Initial Catalog=PE.LayerArtitecture;Integrated Security=True;</connectionString> 
      <commandText> 
        insert into NLog_Error ([time_stamp],[level],[host],[type],[source],[logger],[message],[stacktrace],[allxml]) values(@time_stamp,@level,@host,@type,@source,@logger,@message,@stacktrace,@allxml); 
      </commandText> 
      <parameter name="@time_stamp" layout="${date}" /> 
      <parameter name="@level" layout="${level}" /> 
      <parameter name="@host" layout="${machinename}" /> 
      <parameter name="@type" layout="${exception:format=type}" /> 
      <parameter name="@source" layout="${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false}" /> 
      <parameter name="@logger" layout="${logger}" /> 
      <parameter name="@message" layout="${message}" /> 
      <parameter name="@stacktrace" layout="${exception:stacktrace}" /> 
      <parameter name="@allxml" layout="${xml-encode}" /> 
    </target> 
  </targets> 
  <rules> 
    <!-- add your logging rules here --> 
    <logger minlevel="Info" name="*" writeTo="databaselog" /> 
  </rules> 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM