Serilog文档翻译系列(七)

Serilog文档翻译系列(七) Serilog 文档翻译系列

01、应用设置

Serilog 支持在 App.config 和 Web.config 文件中使用简单的 配置语法,以设置最低日志级别、为事件添加额外属性以及控制日志输出。

Serilog 主要通过代码进行配置,设置支持旨在作为补充功能。虽然不是全面的,但大多数日志记录配置任务都可以通过它实现。

1、启用 配置

需要从 NuGet 安装 支持包:

Install-Package Serilog.Settings.AppSettings

要从 读取配置,可以在 LoggerConfiguration 上使用 ReadFrom.AppSettings() 扩展方法:

Log.Logger = new LoggerConfiguration()
  .ReadFrom.AppSettings()
  ... // Other configuration here, then
  .CreateLogger()

你可以组合使用 XML 和基于代码的配置,但每个接收器(sink)必须通过 XML 或代码进行配置 - 通过代码添加的接收器不能通过应用程序设置进行修改。

2、配置日志记录器

要配置日志记录器,应在程序的 App.config 或 Web.config 文件中包含一个 元素。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add **key**="serilog:minimum-level" **value**="Verbose" />
    <!-- More settings here -->

设置最低日志级别

要为应用程序设置日志级别,请使用 serilog:minimum-level 设置键。

<add **key**="serilog:minimum-level" **value**="Verbose" />

有效值是 LogEventLevel 枚举中定义的值:Verbose、Debug、Information、Warning、Error、Fatal。

添加接收器

接收器通过 serilog:write-to 键添加。设置名称与在代码中使用的配置方法名称相匹配,因此以下两者是等效的:

  .WriteTo.LiterateConsole()

在 XML 中:

  <add **key**="serilog:write-to:LiterateConsole" />

注意:使用 serilog:* 键时需要确保唯一性。

接收器程序集必须使用 serilog:using 语法进行指定。例如,要配置:

  <add **key**="serilog:using:LiterateConsole" **value**="Serilog.Sinks.Literate" />
  <add **key**="serilog:write-to:LiterateConsole"/>

如果接收器接受参数,则通过将参数名称附加到设置后面来指定这些参数。

  .WriteTo.RollingFile(@"C:\Logs\myapp-{Date}.txt", retainedFileCountLimit: 10)

在 XML 中:

  <add **key**="serilog:using:RollingFile" **value**="Serilog.Sinks.RollingFile" />
  <add **key**="serilog:write-to:RollingFile.pathFormat" **value**="C:\Logs\myapp-{Date}.txt" />
  <add **key**="serilog:write-to:RollingFile.retainedFileCountLimit" **value**="10" />

在设置值中指定的任何环境变量(例如 %TEMP%)在读取时将被适当地展开。

使用来自额外程序集的接收器扩展

要使用来自额外程序集的接收器和丰富器,请通过 serilog:using 键进行指定。

例如,要使用来自 Serilog.Sinks.EventLog 程序集的配置:

  <add **key**="serilog:using:EventLog" **value**="Serilog.Sinks.EventLog" />
  <add **key**="serilog:write-to:EventLog.source" **value**="Serilog Demo" />

通过属性丰富日志

要向日志事件附加额外的属性,请使用 serilog:enrich:with-property 指令进行指定。

例如,要将属性 Release 添加到所有事件,并赋值为 "1.2-develop":

  <add **key**="serilog:enrich:with-property:Release" **value**="1.2-develop" />

添加最小级别覆盖

自 Serilog 2.1 起,可以添加最小级别覆盖,以更改某些特定命名空间的最小级别。这是通过设置键 serilog:minimum-level:override: 后跟源上下文前缀来实现的。

例如,以下两者是等效的:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Error)

在 XML 中:

    <add **key**="serilog:minimum-level" **value**="Information" />
    <add **key**="serilog:minimum-level:override:Microsoft" **value**="Warning" />
    <add **key**="serilog:minimum-level:override:Microsoft.AspNetCore.Mvc" **value**="Error" />

02、调试和诊断

当 Serilog 的行为不符合你的预期时,这可能是由于内部异常或配置问题引起的。以下是几种解决问题的方法。

1、SelfLog

首先,如果提供了用户指定的输出,Serilog 将会写入简单的诊断消息。在程序启动时调用 SelfLog.Enable():

Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));

系统控制台、文件或内存中的 StringWriter 都可以通过提供一个 TextWriter 来收集 Serilog 的输出,而不是使用委托:

Serilog.Debugging.SelfLog.Enable(Console.Error);

Serilog 不会将自己的事件写入用户定义的接收器。

警告: SelfLog 不会对提供的 TextWriter 执行任何同步。对于大多数实现,您应该使用 TextWriter.Synchronized() 方法,以确保传入的对象可以从多个线程写入:

var file = File.CreateText(...);
Serilog.Debugging.SelfLog.Enable(TextWriter.Synchronized(file));

2、调试符号

大多数 Serilog 包在 symbolsource 上包含调试符号(_.PDB) - 在 Visual Studio 中将其添加为符号服务器可以帮助确定来自接收器的异常原因。

3、Serilog 分析器

这是一个基于 Roslyn 的分析工具,用于使用 Serilog 日志库的代码。它检查常见错误和使用问题。您可以在这里找到更多信息。

03、开发接收器

以下示例使用 dotnet 命令创建一个项目。

1、创建项目

mkdir SimpleSink
cd SimpleSink
dotnet new console

添加依赖项

从 NuGet 添加 Serilog 包:

dotnet add package serilog

2、构建一个简单的接收器

包含以下 using 语句。这些语句用于接收器类以及配置 Serilog。

using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;

创建接收器

接收器只是实现了 ILogEventSink 接口的类。以下示例将每条消息(无论日志级别如何)渲染到控制台。

public class MySink : ILogEventSink
{
    private readonly IFormatProvider _formatProvider;
    public MySink(IFormatProvider formatProvider)
    {
        _formatProvider = formatProvider;
    }
    public void Emit(LogEvent logEvent)
    {
        var message = logEvent.RenderMessage(_formatProvider);
        Console.WriteLine(DateTimeOffset.Now.ToString() + " "  + message);
    }
}

配置扩展

在配置接收器时,通常会使用一种模式,为 LoggerSinkConfiguration 提供一个扩展方法类。以下代码通过在配置 Serilog 时暴露 MySink 选项来说明这种方法。

public static class MySinkExtensions
{
    public static LoggerConfiguration MySink(
              this LoggerSinkConfiguration loggerConfiguration,
              IFormatProvider formatProvider = null)
    {
        return loggerConfiguration.Sink(new MySink(formatProvider));
    }
}

使用接收器

如在配置基础知识中所示,可以按如下方式配置新的接收器。

var log = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.MySink()
    .CreateLogger();

释放资源

如果接收器实现了 IDisposable,当调用 Log.CloseAndFlush()(使用静态 Log 类时)或者直接释放写入接收器的 Logger 时,Serilog 将调用其 Dispose() 方法。

处理错误和异常

如果接收器无法接受或成功处理事件,它可以(并且应该)从 Emit() 中抛出异常,以通知 Serilog。除非接收器明确配置为审计,Serilog 将抑制该异常并向 SelfLog 写入标准诊断消息。

接收器还可以将诊断消息写入 SelfLog,但应谨慎使用,以避免对性能产生不良影响。

线程安全

接收器构造完成后必须完全线程安全,并接受来自任何线程的 Emit() 调用。Serilog 将并发调用 Emit()。

3、完整示例

以下是作为控制台应用程序的完整示例代码。

using System;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;
namespace SimpleSink
{
    class Program
    {
        static void Main(string[] args)
        {
            var log = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.MySink()
                .CreateLogger();
            var position = new { Latitude = 25, Longitude = 134 };
            var elapsedMs = 34;
            log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
        }
    }
    public class MySink : ILogEventSink
    {
        private readonly IFormatProvider _formatProvider;
        public MySink(IFormatProvider formatProvider)
        {
            _formatProvider = formatProvider;
        }
        public void Emit(LogEvent logEvent)
        {
            var message = logEvent.RenderMessage(_formatProvider);
            Console.WriteLine(DateTimeOffset.Now.ToString() + " "  + message);
        }
    }
    public static class MySinkExtensions
    {
        public static LoggerConfiguration MySink(
                  this LoggerSinkConfiguration loggerConfiguration,
                  IFormatProvider formatProvider = null)
        {
            return loggerConfiguration.Sink(new MySink(formatProvider));
        }
    }
}

示例输出

17/01/2017 3:10:26 PM +10:00 Processed { Latitude: 25, Longitude: 134 } in 034 ms.

:相关源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner

评论