65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 最佳日志库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (21投票s)

2019 年 2 月 22 日

CPOL

16分钟阅读

viewsIcon

67914

在本文中,我们将学习如何在 ASP.NET MVC 应用程序中实现市场上最好的日志库。

引言

什么是日志记录?

日志记录是保存日志的行为。日志文件是记录应用程序所有事件或错误的文件的文件。

参考:- https://en.wikipedia.org/wiki/Log_file

日志记录是应用程序的重要组成部分;尽管我们尽力构建无错误的应用程序,但仍然存在一些条件性错误。为了记录这类错误,我们需要使用一些日志库。例如,有些错误可能是由于数据库服务器宕机或某些应用程序功能无法正常工作而引起的。如果我们没有适当的日志记录设置,我们就无法知道客户端的哪些功能无法正常工作。开发者中有句名言:“在我机子上能跑”。要了解您的应用程序中出了什么问题,日志记录至关重要。

图标由 Freepik 在 www.flaticon.com 制作,根据 CC 3.0 BY 许可。

4 个日志库

我们将详细介绍如何在 ASP.NET MVC 应用程序中实现这 4 个日志库。

1. Log4net  (将日志记录到文本文件 + 将日志记录到 SQL 数据库)

2. Nlog  (将日志记录到文本文件 + 将日志记录到 SQL 数据库)

3. Serilog  (将日志记录到文本文件 + 将日志记录到 SQL 数据库)

4. Elmah (将日志记录到 SQL 数据库)

源代码可在 Github 上找到,链接在文章末尾提供。

创建 ASP.NET 应用程序

让我们开始创建一个名为“WebErrorLogging”的简单的 ASP.NET Web 应用程序,使用 4.5 ASP.NET 模板。

创建应用程序后,我们将首先介绍如何实现 Log4net。

Log4net

什么是 Apache log4net?

Apache log4net 库是一个工具,可以帮助程序员将日志语句输出到各种输出目标。

定义参考:- https://logging.apache.ac.cn/log4net/

从 NuGet 添加项目引用

我们将从 NuGet 包安装 log4net。

添加 log4net 引用后,接下来我们将配置它以记录错误。

我们将看到 Log4net 的 2 种日志记录方式

  1. 在文本文件中
  2. 在数据库中

Log4net 文本文件日志记录

让我们从文本文件日志记录开始。为此,在 Log4net 中,我们需要在 web.config 文件中添加配置。为了在文本文件中记录消息,我们将使用“RollingLogFileAppender”类。

RollingLogFileAppender 根据大小或日期或两者来滚动日志文件。

RollingFileAppender 基于 FileAppender 构建,并具有与该 Appender 相同的选项。

将此配置添加到 web.config 文件将开始向文件写入日志消息。

<configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
 </configSections>

<log4net>
    <root>
      <level value="ALL"></level>
      <appender-ref ref="RollingLogFileAppender"></appender-ref>
    </root>
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="E:\DemoProject\WebErrorLogging\WebErrorLogging\ErrorLog\logfile.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <datePattern value="yyyyMMdd" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="1MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern 
        value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
</log4net>

正如您在上面的配置设置中看到的,这些设置必须添加到 web.config 文件的“<configuration>”标记内。

然后在 log4net 元素内,我们可以在其标签内看到 root 元素,其中我们有另外 2 个子元素,一个是 level,另一个是 appender-ref。

appender-ref:- 允许零个或多个元素。允许日志记录器按名称引用 Appender。

level:- 可选元素,最多允许一个。定义此日志记录器的日志级别。此日志记录器将仅接受等于或高于此级别的事件。

不同的日志级别

  • ALL
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • 致命错误

RollingLogFileAppender

如果您可以看到名为“RollingLogFileAppender”的主要元素 Appender,其中有一个子元素 file,我们可以在其中配置日志记录文件的路径。

示例:-

<file value="ErrorLog/log.txt" />

注意:- 我将路径设置为“ErrorLog/log.txt”,因为我在该应用程序内创建了一个 ErrorLog 文件夹。

下一个元素是 appendToFile。

appendToFile

如果值设置为 false,则文件将被覆盖;如果设置为 true,则文件将被追加。

RollingStyle

名称

描述

一次

每次程序执行时滚动文件

大小

仅根据文件大小滚动文件

日期

仅根据日期滚动文件

复合

根据文件大小和日期滚动文件

参考来源:- https://logging.apache.ac.cn/

maxSizeRollBackups

如果我们设置最大文件大小为 1MB,maxSizeRollBackups 为 10 MB,它将仅保留最后 10 个 MB 的文件,具体取决于日期或文件大小。

web.config 文件快照

我在下面提供快照,以供参考,了解如何将元素正确添加到 web.config 文件中。

在 web.config 文件中添加配置后,接下来我们将初始化 Log4net。

 初始化 Log4net

我们需要调用 XmlConfigurator 类的 configure 方法来初始化 Log4net。

log4net.Config.XmlConfigurator.Configure();

在 global.asax 中初始化 XmlConfigurator 方法后,现在为了演示,我添加了一个名为 DefaultController 的控制器,其中包含 index 操作方法,在该方法中演示如何使用它来记录错误和调试信息。

代码片段

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using log4net;

namespace WebErrorLogging.Controllers
{
    public class DefaultController : Controller
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(DefaultController));

        // GET: Default

        public ActionResult Index()
        {
            try
            {
                Log.Debug("Hi I am log4net Debug Level");
                Log.Info("Hi I am log4net Info Level");
                Log.Warn("Hi I am log4net Warn Level");
                throw new NullReferenceException();
                return View();
            }
            catch (Exception ex)
            {
                Log.Error("Hi I am log4net Error Level", ex);
                Log.Fatal("Hi I am log4net Fatal Level", ex);
                throw;
            }
        }
    }
}

添加控制器并获取 LogManager 类实例后,我们已经记录了各种级别的消息。      

现在让我们通过运行应用程序进行测试。

已记录错误的文件

现在我们完成了将应用程序记录到文本文件,接下来我们将把异常记录到数据库中。

Log4net 数据库日志记录

要将日志记录到数据库,我们首先需要在数据库中创建一个表。

创建表的脚本

CREATE TABLE [dbo].[Log](
       [Id] [int] IDENTITY(1,1) NOT NULL,
       [Date] [datetime] NOT NULL,
       [Thread] [varchar](255) NOT NULL,
       [Level] [varchar](50) NOT NULL,
       [Logger] [varchar](255) NOT NULL,
       [Message] [varchar](4000) NOT NULL,
       [Exception] [varchar](2000) NULL
) ON [PRIMARY]

在数据库中创建 Log 表后,接下来我们将添加一种新的 Appender 类型,即“log4net.Appender.AdoNetAppender

将此配置添加到 web.config 文件将开始向数据库表写入日志消息。

为此,我们需要数据库的连接字符串,我们将在此记录错误。如果您查看下面的配置,您将看到 connectionStrings 元素,其中我添加了数据库连接设置,我们将把 connectionStrings 分配给“AdoNetAppender”。

如果您在“AdoNetAppender”中看到 commandText 元素,您将在其中看到 insert 语句的脚本。

我们需要设置的主要内容是“appender-ref”。在这里,我们将日志消息记录到数据库。为此,我们将设置引用 (ref) 为“AdoNetAppender”。

<appender-ref ref="AdoNetAppender"></appender-ref>

配置设置

<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
  </configSections>
  <connectionStrings>
    <add name="ConnectionStringLogging" 
    connectionString="data source=SAI-PC\SQLEXPRESS;
    initial catalog=LoggingDatabase;
    integrated security=false;persist security info=True;User ID=sa;Password=Pass$123" 
    providerName="System.Data.SqlClient" />
  </connectionStrings>
  <log4net>
    <root>
      <level value="ALL"></level>
      <appender-ref ref="AdoNetAppender"></appender-ref>
    </root>
    <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
      <bufferSize value="1" />
      <connectionType 
      value="System.Data.SqlClient.SqlConnection,System.Data, 
      Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <connectionStringName value="ConnectionStringLogging" />
      <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) 
      VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
      <parameter>
        <parameterName value="@log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@thread" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%thread" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@log_level" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
    </appender>
  </log4net>
</configuration>

web.config 文件快照

我在下面提供快照,以供参考,了解如何将元素正确添加到 web.config 文件中。

现在我们将运行与用于将消息记录到文本文件的应用程序相同的应用程序,但这次我们将消息记录到数据库。

现在让我们通过运行应用程序进行测试。

错误已记录到数据库

运行应用程序并访问 Default Controller 后,消息将记录在数据库中,如下所示。

在完成理解 Log4net 后,接下来我们将继续介绍如何使用 Nlog 来记录消息。

Nlog

什么是 Nlog?

NLog 是一个灵活的免费日志平台,适用于各种 .NET 平台,包括 .NET Standard。NLog 可以轻松地写入到多个目标(数据库、文件、控制台),并可以动态更改日志配置。

参考来源:- https://nlog-project.org/

从 NuGet 添加项目引用

我们将从 NuGet 包安装 2 个包:NLog 和 NLog.Config。

添加 NLog 引用后,接下来我们将配置它以记录错误。

我们将看到 NLog 的 2 种日志记录方式

  1. 在文本文件中
  2. 在数据库中 

Nlog 文本文件日志记录

信号强度

典型用法

Fatal(致命)

发生了糟糕的事情;应用程序正在崩溃

Error(错误)

出错了;应用程序可能继续也可能不继续

Warn(警告)

意外情况;应用程序将继续运行

Info(信息)

正常行为,如发送邮件、用户更新个人资料等。

Debug

用于调试;执行的查询、已验证的用户、会话过期

Trace

用于跟踪调试;开始方法 X,结束方法 X

参考来源:https://github.com/NLog/NLog/wiki/Configuration-file#log-levels

让我们从文本文件日志记录开始。为此,在 NLog 中,我们需要在 web.config 文件中添加配置以写入文本文件。

代码片段

<configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
  </configSections>

  <nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
      <target name="logfile" xsi:type="File"
              maxArchiveFiles="10"
              archiveAboveSize="5242880"
              archiveEvery="Minute"
              archiveNumbering="Sequence"
              fileName="${basedir}/ErrorLog/logfile.txt"
              layout="------${level}(${longdate})${machinename}------${newline}
                      Exception Type:${exception:format=Type} |
                      Exception Message:${exception:format=Message} |
                      Stack Trace:${exception:format=Stack Trace} |
                      Additional Info:${message}${newline}" />
    </targets>
    <rules>
      <logger name="*" minlevel="Trace" writeTo="logfile" />
    </rules>
  </nlog>

您可以根据需要设置大量选项。您可以根据时间或文件大小来存档日志。在此示例中,我根据时间和大小进行了设置,对于时间,我设置了 archiveEvery="Minute",对于大小,我提供了 archiveAboveSize="5242880",大小以字节为单位 5MB =” 5,242,880” 字节。

链接:- https://github.com/nlog/NLog/wiki/File-target

web.config 文件快照

我在下面提供快照,以供参考,了解如何将元素正确添加到 web.config 文件中。

​​​​​​

配置 NLog 后,接下来我们将添加 DefaultController 和 index 操作方法来记录日志。接下来,我们将使用 LogManager 类来创建 Logger 实例。

代码片段

public class DefaultController : Controller
    {
        public readonly Logger Logger = NLog.LogManager.GetCurrentClassLogger();
        // GET: Default
        public ActionResult Index()
        {
            try
            {
                Logger.Debug("Hi I am NLog Debug Level");
                Logger.Info("Hi I am NLog Info Level");
                Logger.Warn("Hi I am NLog Warn Level");
                throw new NullReferenceException();
                return View();
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Hi I am NLog Error Level");
                Logger.Fatal(ex, "Hi I am NLog Fatal Level");
                throw;
            }
        }
    }

创建 Logger 实例后,我们将调用各种 logger 级别的方法来记录消息。

现在让我们通过运行应用程序进行测试。

已记录错误的文件

现在我们已经完成了将消息记录到文本文件,接下来通过对配置文件进行一些更改,我们将把消息记录到数据库中,步骤很简单。

NLog 数据库日志记录

要将日志记录到数据库,我们首先需要在数据库中创建一个表。

创建表的脚本

CREATE TABLE [dbo].[NLog](
    [id] [int] IDENTITY(1,1) NOT NULL Primary key,
    [timestamp] [datetime] NOT NULL,
    [level] [varchar](100) NOT NULL,
    [logger] [varchar](1000) NOT NULL,
    [message] [varchar](3600) NOT NULL,
    [Callsite] [varchar](3600) NULL,
    [exception] [varchar](3600) NULL
) 

完成创建 NLog 表后,接下来我们将向现有 web.config 文件添加配置设置以记录到数据库。

我们只需要在现有的 NLog 配置中添加一个具有新名称的新目标。此目标包含数据库连接字符串以及将日志插入数据库的 SQL insert 语句。下一步,我们需要在 rules 元素中将参数(包含要记录的数据)传递给目标,同时我们需要在 Log Levels (“Trace”) 下注册目标 (“database”)。    

用于记录到数据库的配置设置

<target name="database" type="Database" 
connectionString="data source=SAI-PC\SQLEXPRESS;
initial catalog=LoggingDatabase;
integrated security=false;
persist security info=True;
User ID=sa;Password=Pass$123">
        <commandText> insert into NLog ([TimeStamp],[Level],Logger, [Message], Callsite, Exception) 
        values (@TimeStamp, @Level, @Logger, @Message, @Callsite, @Exception); </commandText>
        <parameter name="@TimeStamp" layout="${date}" />
        <parameter name="@Level" layout="${level}" />
        <parameter name="@Logger" layout="${logger}" />
        <parameter name="@Message" layout="${message}" />
        <parameter name="@Callsite" layout="${callsite}" />
        <parameter name="@Exception" layout="${exception:tostring}" />
        <dbProvider>System.Data.SqlClient</dbProvider>
      </target>
    <rules>
      <logger name="*" minlevel="Trace" writeTo="database" />
    </rules>

注意:- * - 匹配零个或多个字符。

添加用于记录消息到数据库的新目标的 web.config 文件快照

现在让我们通过运行应用程序进行测试。

错误已记录到数据库

运行应用程序并访问 Default Controller 后,消息将记录在数据库中,如下所示。

完成理解 Nlog 后,接下来我们将继续介绍如何使用 Serilog Log 来记录消息。

Serilog

什么是 Serilog?

Serilog 是一个面向 .NET 应用程序的诊断日志记录库。它易于设置,具有清晰的 API,并运行在所有最近的 .NET 平台上。虽然它即使在最简单的应用程序中也很有用,但 Serilog 对结构化日志的支持在仪器化复杂、分布式和异步应用程序和系统时尤为突出。

我们将看到 Serilog 的 2 种日志记录方式

  1. 在文本文件中
  2. 在数据库中 

 

从 NuGet 添加项目引用

我们将从 NuGet 包安装 2 个包:“Serilog”“Serilog.Sinks.File”

Serilog:- Serilog 是一个 .NET 应用程序的日志记录库。

Serilog.Sinks.File:- 此包用于将日志消息写入文本文件。

添加这两个包后,接下来我们将查看 Log Event Levels。

日志事件级别

Serilog 使用级别作为分配日志事件重要性的主要手段。级别按重要性递增的顺序为:

接下来,我编写了一个辅助类,其中包含用于集中事件日志记录的代码。

名称

描述

Verbose(详细)

跟踪信息和调试的细微之处;通常,只在不寻常的情况下启用

Debug

内部控制流程和诊断状态转储,以帮助查明已识别的问题

信息
对于外部观察者感兴趣或有相关性的事件;默认启用的最低日志记录级别
警告 指示可能存在的问题或服务/功能降级
Error(错误) 表示应用程序或连接系统内部发生故障
Fatal(致命) 导致应用程序完全失败的关键错误

参考链接:- https://github.com/serilog/serilog/wiki/Writing-Log-Events

Serilog 文本文件日志记录

让我们开始理解代码。我创建了一个名为 helper 的静态类,以便无需创建对象即可使用它。下一个案例是只初始化这个类一次,这就是为什么我必须使用静态构造函数来初始化它。为了在文本文件中记录,我们创建了 LoggerConfiguration 类的实例,为了记录错误,我将 Minimum level 设置为 error。我们将写入文本文件,但存储在哪里,它将在文件夹中,对吧?为了保持清晰以维护错误,我创建了一个名为“ErrorLog”的主文件夹,在该文件夹内,我需要根据级别创建子文件夹(“Debug”、“Error”、“Warning”...)。现在我们需要将消息写入此文件夹,为此,我们需要设置路径,我们将使用“WriteTo.File”方法并将其作为字符串传递路径。接下来,我们不能将错误消息记录到一个大的文本文件中,因为这无助于我们轻松跟踪已记录的消息。另一个原因是如果文件大小变大,我们就无法轻松打开该文件。为了应对这种情况,我们可以使用“rollingInterval”和“rollOnFileSizeLimit”属性。在 rollingInterval 中,我们可以使用“RollingInterval”参数(如  (Infinite, Year, Month, Day, Hour, Minute))滚动文件,在“rollOnFileSizeLimit”中,我们可以设置以字节为单位的文件大小限制。为此,我们需要设置“fileSizeLimitBytes”属性,并将 rollOnFileSizeLimit 设置为 true。现在,在创建实例后,我创建了适合不同级别的不同方法,以便我们可以根据需要使用不同的方法。

    

辅助类代码片段

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Serilog;
using Serilog.Events;

namespace WebErrorLogging.Utilities
{
    public static class Helper
    {
        private static readonly ILogger Errorlog;
        private static readonly ILogger Warninglog;
        private static readonly ILogger Debuglog;
        private static readonly ILogger Verboselog;
        private static readonly ILogger Fatallog;

        static Helper()
        {

            // 5 MB = 5242880 bytes

            Errorlog = new LoggerConfiguration()
                .MinimumLevel.Error()
               .WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/ErrorLog/Error/log.txt"),
                rollingInterval: RollingInterval.Day,
                fileSizeLimitBytes: 5242880,
                rollOnFileSizeLimit: true)
                .CreateLogger();

            Warninglog = new LoggerConfiguration()
                .MinimumLevel.Warning()
              .WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/ErrorLog/Warning/log.txt"),
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 5242880,
                    rollOnFileSizeLimit: true)
                .CreateLogger();

            Debuglog = new LoggerConfiguration()
                .MinimumLevel.Debug()
              .WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/ErrorLog/Debug/log.txt"),
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 5242880,
                    rollOnFileSizeLimit: true)
                .CreateLogger();

            Verboselog = new LoggerConfiguration()
                .MinimumLevel.Verbose()
              .WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/ErrorLog/Verbose/log.txt"),
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 5242880,
                    rollOnFileSizeLimit: true)
                .CreateLogger();

            Fatallog = new LoggerConfiguration()
                .MinimumLevel.Fatal()
              .WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/ErrorLog/Fatal/log.txt"),
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 5242880,
                    rollOnFileSizeLimit: true)
                .CreateLogger();

        }

        public static void WriteError(Exception ex, string message)
        {
            //Error - indicating a failure within the application or connected system
            Errorlog.Write(LogEventLevel.Error, ex, message);
        }

        public static void WriteWarning(Exception ex, string message)
        {
            //Warning - indicators of possible issues or service / functionality degradation
            Warninglog.Write(LogEventLevel.Warning, ex, message);
        }

        public static void WriteDebug(Exception ex, string message)
        {
            //Debug - internal control flow and diagnostic state dumps to facilitate 
            //          pinpointing of recognised problems
            Debuglog.Write(LogEventLevel.Debug, ex, message);
        }

        public static void WriteVerbose(Exception ex, string message)
        {
            // Verbose - tracing information and debugging minutiae; 
            //             generally only switched on in unusual situations
            Verboselog.Write(LogEventLevel.Verbose, ex, message);
        }

        public static void WriteFatal(Exception ex, string message)
        {
            //Fatal - critical errors causing complete failure of the application
            Fatallog.Write(LogEventLevel.Fatal, ex, message);
        }

        public static void WriteInformation(Exception ex, string message)
        {
            //Fatal - critical errors causing complete failure of the application
            Fatallog.Write(LogEventLevel.Fatal, ex, message);
        }

    }
}    

创建辅助类后,接下来我们将 DefaultController 的 index 操作方法中的这个辅助类调用,以测试和记录所有类型的消息。

DefaultController 代码片段 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebErrorLogging.Utilities;

namespace WebErrorLogging.Controllers
{
    public class DefaultController : Controller
    {

        // GET: Default
        public ActionResult Index()
        {
            try
            {
                Helper.WriteDebug(null, "Debug ");
                Helper.WriteWarning(null, "Warning ");
                throw new NotImplementedException();
            }
            catch (Exception e)
            {
                Helper.WriteError(e, "Error");
                Helper.WriteFatal(e, "Fatal");
                Helper.WriteVerbose(e, "Verbose");
                throw;
            }

            return View();
        }
    }
}

将辅助类添加到 DefaultController 的日志记录消息后,接下来我们将保存应用程序并进行测试。

最终输出

使用 Serilog 将消息记录到文本文件后的最终输出。

使用 Serilog 完成文本文件消息日志记录后,接下来我们将学习如何使用相同的 Serilog 但需要一个额外的 NuGet 包来将消息记录到 SQL 数据库。

Serilog 数据库日志记录

在这一部分,我们将把消息记录到 SQL 数据库。为此,我们将向现有解决方案添加新的 NuGet 包“Serilog.Sinks.MSSqlServer”。

从 NuGet 添加项目引用

安装 NuGet 包后,现在我们将编写一个类似于我们为文本文件日志记录编写的辅助类,但这次我们将把消息记录到数据库。

为此,我们将首先创建一个表。

创建表的脚本

CREATE TABLE [dbo].[Serilogs](
    [Id] [int] IDENTITY(1,1) NOT NULL Primary Key,
    [Message] [nvarchar](max) NULL,
    [MessageTemplate] [nvarchar](max) NULL,
    [Level] [nvarchar](128) NULL,
    [TimeStamp] [datetime] NULL,
    [Exception] [nvarchar](max) NULL,
    [Properties] [xml] NULL)

创建表后,接下来我们将编写一个名为“HelperStoreSqlLog”的辅助类,我们将在此集中日志记录并将消息存储在 Serilog 的表中。

设置数据库日志记录时有 3 个要点需要关注。

  1. 在 web.config 文件中检查数据库的正确连接字符串
  2. 在数据库中创建 Serilog 表。
  3. 使用 WriteTo.MSSqlServer 方法将消息和错误写入数据库。此方法接受 2 个参数作为输入,一个是要写入的连接字符串,另一个是您的表。

代码片段

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Serilog;
using Serilog.Events;

namespace WebErrorLogging.Utilities
{
    public static class HelperStoreSqlLog
    {
        private static readonly ILogger Errorlog;
        private static readonly ILogger Warninglog;
        private static readonly ILogger Debuglog;
        private static readonly ILogger Verboselog;
        private static readonly ILogger Fatallog;
        private static readonly string ConnectionString = 
         ConfigurationManager.ConnectionStrings["ConnectionStringLogging"].ToString();

        static HelperStoreSqlLog()
        {

            Errorlog = new LoggerConfiguration()
                .MinimumLevel.Error()
                .WriteTo.MSSqlServer(ConnectionString, "Serilogs")
                .CreateLogger();

            Warninglog = new LoggerConfiguration()
                .MinimumLevel.Warning()
                .WriteTo.MSSqlServer(ConnectionString, "Serilogs")
                .CreateLogger();

            Debuglog = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.MSSqlServer(ConnectionString, "Serilogs")
                .CreateLogger();

            Verboselog = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.MSSqlServer(ConnectionString, "Serilogs")
                .CreateLogger();

            Fatallog = new LoggerConfiguration()
                .MinimumLevel.Fatal()
                .WriteTo.MSSqlServer(ConnectionString, "Serilogs")
                .CreateLogger();

        }

        public static void WriteError(Exception ex, string message)
        {
            //Error - indicating a failure within the application or connected system
            Errorlog.Write(LogEventLevel.Error, ex, message);
        }

        public static void WriteWarning(Exception ex, string message)
        {
            //Warning - indicators of possible issues or service / functionality degradation
            Warninglog.Write(LogEventLevel.Warning, ex, message);
        }

        public static void WriteDebug(Exception ex, string message)
        {
            //Debug - internal control flow and diagnostic 
            // state dumps to facilitate pinpointing of recognised problems
            Debuglog.Write(LogEventLevel.Debug, ex, message);
        }

        public static void WriteVerbose(Exception ex, string message)
        {
            // Verbose - tracing information and debugging minutiae; 
            //   generally only switched on in unusual situations
            Verboselog.Write(LogEventLevel.Verbose, ex, message);
        }

        public static void WriteFatal(Exception ex, string message)
        {
            //Fatal - critical errors causing complete failure of the application
            Fatallog.Write(LogEventLevel.Fatal, ex, message);
        }

        public static void WriteInformation(Exception ex, string message)
        {
            //Fatal - critical errors causing complete failure of the application
            Fatallog.Write(LogEventLevel.Fatal, ex, message);
        }
    }
} 

创建 HelperStoreSqlLog 后,接下来我们将 DefaultController 的 index 操作方法中的这个 HelperStoreSqlLog 类调用,以测试和记录所有类型的消息。

代码片段

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebErrorLogging.Utilities;

namespace WebErrorLogging.Controllers
{
    public class DefaultController : Controller
    {
        // GET: Default   
        public ActionResult Index()
        {
            try
            {
                HelperStoreSqlLog.WriteDebug(null, "Debug ");
                HelperStoreSqlLog.WriteWarning(null, "Warning ");
                throw new NotImplementedException();
            }
            catch (Exception e)
            {
                HelperStoreSqlLog.WriteError(e, "Error");
                HelperStoreSqlLog.WriteFatal(e, "Fatal");
                HelperStoreSqlLog.WriteVerbose(e, "Verbose");
                throw;
            }
            return View();
        }
    }
}

将 HelperStoreSqlLog 类添加到 DefaultController 的日志记录消息后,接下来我们将保存应用程序并进行测试。

 最终输出

使用 Serilog 将消息记录到数据库后的最终输出。

我们已经完成了使用 Serilog 进行消息日志记录。接下来,我们将看一些我们可以使用 Serilog 的 appsettings 进行的配置。

Serilog.Settings.AppSettings    

到目前为止,我们已经完全通过代码配置了 Serilog。现在我们将使用 appsettings 来进行相同的文本文件消息日志记录配置。

安装包后,接下来我们将进行 appsettings 的配置设置。

使用“Serilog.Settings.AppSettings”在 appsettings 中记录文本文件消息的配置

  <appSettings>

    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />

    <!-- appSettings for Serilog Storing in Text file  -->
    <add key="serilog:minimum-level" value="Verbose" />
    <add key="serilog:using:File" value="Serilog.Sinks.File" />
    <add key="serilog:write-to:File.path" 
         value="E:\DemoProject\WebErrorLogging\WebErrorLogging\ErrorLog\Error\log.txt" />
    <add key="serilog:write-to:File.fileSizeLimitBytes" value="1234567" />
    <add key="serilog:write-to:RollingFile.retainedFileCountLimit" value="10" />
    <add key="serilog:write-to:File.rollingInterval" value="Day"/>
    <!-- appSettings for Serilog Storing in Text file  -->

  </appSettings>

在 appsettings 中配置后,接下来我们将对代码进行一些小改动以使其正常工作。

代码片段

代码中配置的主要部分是使用“.ReadFrom.AppSettings()”方法来读取我们已配置的 appsettings 中的配置。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Serilog;
using WebErrorLogging.Utilities;

namespace WebErrorLogging.Controllers
{
    public class DefaultController : Controller
    {
        private ILogger _errorlog;
        public ActionResult Index()
        {
            try
            {
                throw new NotImplementedException();
            }
            catch (Exception e)
            {
                _errorlog = new LoggerConfiguration()
                    .ReadFrom.AppSettings()
                    .CreateLogger();

                _errorlog.Error(e, "DefaultController");
                throw;
            }
            return View();
        }
    }
}  

添加 Serilog.Settings.AppSettings 后,接下来我们将保存应用程序并进行测试。

 最终输出

最后,我们已经完成了使用 serilog 进行消息日志记录。接下来,我们将看看我们最后一个最佳日志选项 ELMAH。

ELMAH

什么是 ELMAH?

错误日志模块和处理程序 (ELMAH)。

  • 记录几乎所有未处理的异常。
  • 一个网页,用于远程查看已记录异常的完整日志。
  • 一个网页,用于远程查看任何已记录异常的完整详细信息,包括彩色堆栈跟踪。
  • 在许多情况下,即使在自定义 Errors 模式关闭的情况下,您也可以查看 ASP.NET 为特定异常生成的原始蓝屏死机。
  • 在发生错误时通过电子邮件通知。
  • 来自日志的最后 15 个错误的 RSS Feed。

参考来源:- https://code.google.com/archive/p/elmah/

我们将看到 Elmah 的 1 种日志记录方式

  1. 在数据库中

在这一部分,我们将使用 ELMAH 将错误记录到数据库。为此,我们首先需要从 NuGet 包安装 2 个 ELMAH 包。

ELMAH 数据库日志记录

从 NuGet 添加项目引用

1. Elmah.MVC

2. elmah.sqlserver

在安装 elmah.sqlserver 包时,它会创建一个“App_Readme”文件夹,并在该文件夹中添加用于创建 Elmah 表和存储过程的 SQL 查询脚本。

同样,在安装 elmah 和 elmah.sqlserver 包时,它会在 web.config 文件中添加 XML 配置。在该配置文件中,您将在 connection string 部分看到“elmah-sqlserver”标签。在这里,您需要提供数据库连接设置。

安装 elmah.sqlserver 包后添加的 elmah-sqlserver 标签的片段。

  <connectionStrings>
    <!-- TODO: Replace the ****'s with the correct entries -->
    <add name="elmah-sqlserver" 
         connectionString="Data Source=****;User ID=****;Password=****;Initial Catalog=****;" 
         providerName="System.Data.SqlClient" />
  </connectionStrings>

在用正确的数据库凭据替换“****”以连接到数据库后。

  <connectionStrings>
    <!-- TODO: Replace the ****'s with the correct entries -->
    <add name="elmah-sqlserver" 
         connectionString="Data Source=SAI-PC\SQLEXPRESS;User ID=sa;Password=Pass$123;
         Initial Catalog=LoggingDatabase;" 
         providerName="System.Data.SqlClient" />
  </connectionStrings>

设置连接字符串后,您需要执行 Elmah.Sqlserver 脚本到数据库以生成 Elmah 的表和存储过程。

下面是执行 Elmah SqlServer 脚本后的快照

现在我们已经配置了 ELMAH,让我们创建一个默认控制器,其中包含将引发错误的 index 操作方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace WebErrorLogging.Controllers
{
    public class DefaultController : Controller
    {
        public ActionResult Index()
        {
            try
            {
                throw new NotImplementedException();
            }
            catch (Exception)
            {
                throw;
            }
            return View();
        }
    }
}

添加控制器和 Index 操作后,接下来我们将保存应用程序并进行测试。

输出

使用 ELMAH 将错误记录到数据库后的最终输出。

现在我们已经存储了错误。要在浏览器中查看此错误,我们需要在 web.config 文件中进行如下配置。

1. 添加到 web.config 的片段 在 <system.web> 元素下

片段

<!--Newly Added-->  
    <httpHandlers>  
      <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />  
    </httpHandlers>  
<!--Newly Added-->  

2. 添加到 web.config <system.webServer> 元素下的片段

片段

    <!--Newly Added-->  
    <handlers>  
      <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" 
           type="Elmah.ErrorLogPageFactory, Elmah" />  
    </handlers>  
    <!--Newly Added-->

3. 添加到 web.config <elmah> 元素的片段 

片段

  <elmah>
    <security allowRemoteAccess="0" />  
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" />
  </elmah>

allowRemoteAccess 是什么?

默认情况下,不允许远程访问 /elmah.axd,这意味着在 localhost 以外的其他地方请求该 URL 会返回 HTTP 状态代码 403。不建议公开 ELMAH UI 的远程访问,但在某些情况下可能适用。将 allowRemoteAccess 设置为 1 或 true,可以使 /elmah.axd 在您的公共网站上可访问。

参考来源:- https://blog.elmah.io/elmah-security-and-allowremoteaccess-explained/

现在,要在网页上查看错误,您需要在 URL 末尾输入“elmah.axd”,如 https://:55946/elmah.axd  ,如下所示。

如果您在 IIS 中托管了您的站点,则需要输入类似 http://xyz.com/elmah.axd 的 URL。

最终输出

最后,我们已经以简单的方式学习了如何使用这 4 个最适合 ASP.NET MVC 应用程序日志记录的日志记录器。这些日志记录器已被许多公司在实时生产应用程序中使用。感谢您花费宝贵的时间阅读本文。

Log4Net 源代码链接:- https://github.com/saineshwar/WebErrorLogging_Log4Net

NLog 源代码链接:- https://github.com/saineshwar/WebErrorLogging_NLog

Serilog 源代码链接:- https://github.com/saineshwar/WebErrorLogging_Serilog

ELMAH 源代码链接:- https://github.com/saineshwar/WebErrorLogging_ELMAH

© . All rights reserved.