【问题标题】:Event types to Serilog events in MSSQLMSSQL 中 Serilog 事件的事件类型
【发布时间】:2020-08-18 17:36:28
【问题描述】:

我是 Serilog 的新手。我最近刚刚负责将 Serilog 记录到我们的 MSSQL 数据库。我已经能够做到这一点;但是,我在尝试将事件类型分配给不同的 Serilog 事件时遇到问题。它在我尝试将事件类型信息保存到文本文件时有效,但在写入数据库时​​无效。我已经阅读了许多关于此的不同文章,但我仍然必须遗漏一些东西。任何帮助将不胜感激。我正在使用 .NET Core 3.1。这是我所拥有的。

这是我安装的与 Serilog 相关的 Nuget 包。

  • Serilog.AspNetCore (v 3.2.0)
  • Serilog.Enrichers.Environment (v 2.1.3)
  • Serilog.Enrichers.Process (v 2.0.1)
  • Serilog.Enrichers.Thread (v 3.1.0)
  • Serilog.Settings.Configuration (v 3.1.0)
  • Serilog.Sinks.MSSqlServer (v 5.5.1)
  • Serilog.Sinks.RollingFile (v 3.3.0)
  • MurmurHash-net-core (v 1.0.0)

数据库表

USE [MyDatabase]
GO

/****** Object:  Table [dbo].[Logs]    Script Date: 8/17/2020 6:10:12 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Logs](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Message] [nvarchar](max) NULL,
    [MessageTemplate] [nvarchar](max) NULL,
    [Level] [nvarchar](128) NULL,
    [TimeStamp] [datetimeoffset](7) NOT NULL,
    [Exception] [nvarchar](max) NULL,
    [Properties] [xml] NULL,
    [LogEvent] [nvarchar](max) NULL,
 CONSTRAINT [PK_Logs] 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

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "ConnectionStrings": {
    "DataMart": "Data Source=.\\MSSQLSERVER2K16,53307;Initial Catalog=MyDatabase;Integrated Security=SSPI;MultipleActiveResultSets=True"
  },
  "Serilog": {
    "Using": [ "Serilog.Sinks.MSSqlServer" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Information",
        "System": "Information"
      }
    },
    "WriteTo": [
      {
        "Name": "RollingFile",
        "Args": {
          "pathFormat": "C:\\Temp\\Application-API-log-{Date}.txt",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{EventType:x8} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "MSSqlServer",
        "Args": {
          "connectionString": "Data Source=.\\MSSQLSERVER2k16,53307;Initial Catalog=MyDatabase;Integrated Security=SSPI;MultipleActiveResultSets=True",
          "schemaName": "dbo",
          "tableName": "Logs",
          "autoCreateSqlTable": false,
          "restrictedToMinimumLevel": "Information"
        }
      }
    ],
    "Properties": {
      "Application": "Application Api"
    }
  },
  "AllowedHosts": "*"
}

EventTypeEnricher.cs

class EventTypeEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var murmur = MurmurHash.Create32();
        var bytes = Encoding.UTF8.GetBytes(logEvent.MessageTemplate.Text);
        var hash = murmur.ComputeHash(bytes);
        var numericHash = BitConverter.ToUInt32(hash, 0);
        var eventType = propertyFactory.CreateProperty("EventType", numericHash);
        logEvent.AddPropertyIfAbsent(eventType);
    }
}

Program.cs

public static class Program
{
    public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .Build();

    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .Enrich.With<EventTypeEnricher>()
            .Enrich.WithThreadId()
            .Enrich.WithProcessId()
            .Enrich.WithMachineName()
            .Enrich.WithEnvironmentUserName()
            .CreateLogger();

        Serilog.Debugging.SelfLog.Enable(msg =>
        {
            Debug.Print(msg);
            Debugger.Break();
        });

        try
        {
            Log.Information("Application version {Version} starting up", typeof(Program).Assembly.GetName().Version);
            BuildWebHost(args).Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseConfiguration(Configuration)
            .UseSerilog()
            .Build();
}

【问题讨论】:

  • 任何错误或异常?
  • 我没有看到任何错误。出于某种原因,事件的散列值没有被添加到数据库中。
  • 我刚刚意识到我可能对预期的行为感到困惑。我仍然没有在 LogEvent 列中看到任何内容。但是,当我查看数据库中的 Properties 列时,我能够将每个事件类型的散列值与 4213687506 中的值相匹配。我也停止并启动了应用程序,我注意到每种事件类型都有一个可重复的模式。现在我再看一遍是有道理的。我现在的问题是,有没有办法将此值写入 LogEvent 列而不是作为 Properties 列的键?

标签: c# sql-server .net-core serilog


【解决方案1】:

您可以采取许多步骤来解决您的 SQL Server 接收器无法正常工作的原因。下面的答案中描述了常见的:

Serilog MSSQL Sink doesn't write logs to database

默认情况下,您在日志语句中包含的任何日志事件属性都将保存到 XML 属性列或 JSON LogEvent 列。但它们也可以通过AdditionalColumns 集合存储在各自的列中

Custom Property Columns

【讨论】:

  • 谢谢。我刚刚意识到我可能对预期的行为感到困惑。我仍然没有在 LogEvent 列中看到任何内容。但是,当我查看数据库中的 Properties 列时,我能够将每个事件类型的散列值与 4213687506 中的值相匹配。我也停止并启动了应用程序,我注意到每种事件类型都有一个可重复的模式。现在我再看一遍是有道理的。我现在的问题是,有没有办法将此值写入 LogEvent 列而不是作为 Properties 列的键?
  • @kasabb 要将属性存储在单独的列中,您必须将它们告诉 Serilog。文档中对此进行了解释:Custom Property Columns.
【解决方案2】:

我认为您混淆了 LogEvent、Properties 和 EventType 列。在开始之前,重要的是要知道 LogEvent 是一个令人困惑的名称,因为这也是用于在 serilog 中写入日志的name of the class。本质上,当您编写日志时,会创建一个 LogEvent 对象,其中包含所有数据(手动传递的项目,如消息模板和道具值,自动信息,如时间戳,以及通过丰富器附加的任何附加信息) 的日志。我将使用斜体来表示类。

为了连接这个新属性,您需要通过以下任一方式将列添加到接收器的附加列选项中:

var columnOpts = new ColumnOptions();
columnOpts.Store.Remove(StandardColumn.Properties ); // removes the xml serialization of log event properties
columnOpts.Store.Add(StandardColumn.LogEvent ); // add the json serialization of log event props
columnOpts.AdditionalColumns = new List<SqlColumn>() // tell the sink to create a column for the EventType
{
    new SqlColumn { DataType = SqlDbType.NVarChar, ColumnName = "EventType", AllowNull = true }
};

return new LoggerConfiguration()
    .MinimumLevel.Information()
    .Enrich.With<EventTypeEnricher>()
    .WriteTo.MSSqlServer(connectionString: connString, sinkOptions: sinkOpts, columnOptions: columnOpts, restrictedToMinimumLevel: LogEventLevel.Information )
    .CreateLogger();

您在 Properties 列中看到 EventType 的原因是因为该列捕获了发送到 日志事件的所有数据。

TL;DR LogEvent/Properties 列将 日志事件 的所有数据存储为序列化的 json/xml 字符串。如果您想将 EventType 视为自己的列,则需要告诉接收器创建此列。

【讨论】:

    猜你喜欢
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 2014-03-28
    相关资源
    最近更新 更多