01、记录器的生命周期

Serilog 大多数情况下“只需使用”,并且在创建和处理日志记录器时不需要过多考虑。然而,由于以下原因:

某些接收器(sink)涉及后台进程,特别是那些使用网络的接收器;

一些接收器(尤其是文件和滚动文件接收器)所持有的资源;

因此,某些使用模式在效果和可靠性上表现得更好。

1、在所有应用程序中

使用 Serilog 最简单的方法是通过全局 Log 类:

Log.Logger = new LoggerConfiguration()
.WriteTo.File(@"myapp\log.txt")
.CreateLogger();
Log.Information("Hello!");
// Your application runs, then:
Log.CloseAndFlush();

如果这样做,只需配置一次日志记录器,然后在应用程序的整个生命周期中使用它。

要创建更专业的日志记录器:

调用 Log.ForContext(...) 来接收一个附加了额外属性的 ILogger;这不需要任何特殊的关闭/刷新逻辑,因为这将由父日志记录器处理。

在少数情况下,可以使用单独的 LoggerConfiguration 创建一个额外的 ILogger,并使用 WriteTo.Logger(Log.Logger) 将事件传递到根日志记录器;在这种情况下,必须遵循下面的处置逻辑。

2、不使用 Log

如果您不希望使用静态 Log 类,可以使用 LoggerConfiguration 创建一个 ILogger。

using (var log = new LoggerConfiguration()
.WriteTo.File(@"myapp\log.txt")
.CreateLogger())
{
log.Information("Hello again!");
// Your app runs, then disposal of `log` flushes any buffers
}

在这种情况下,不使用 Log.CloseAndFlush()。相反,当应用程序不再需要日志记录器时,会进行处置。

只有通过 LoggerConfiguration 创建的根日志记录器需要以这种方式处理。从 ForContext() 和类似方法返回的 ILoggers 不需要任何特殊处理。

3、使用 IoC 容器

请参见 Autofac 集成示例,了解如何与 Autofac IoC 容器一起使用可注入的 ILoggers。如果您希望更新此页面以提供其他容器的说明,请提出问题。

02、可靠性

Serilog 认为,综合考虑,日志记录的优先级低于其他应用程序代码,绝不应在可避免的情况下影响正在运行的应用程序的操作。

在实践中,这主要转化为一种处理 Serilog 中异常的策略。在这个过程中会对可用性做出一些妥协。本文档解释了作为 Serilog 库用户您可以期待的内容,以及如果您正在扩展 Serilog,如何编写与其余代码库良好配合的代码。

1、配置

在配置时,即调用 LoggerConfiguration 方法时,错误分为两类。

运行时配置错误

如果由于主机机器的运行时状态无法配置接收器(sink),Serilog 将捕获任何导致的异常并将其写入 SelfLog(参见调试和诊断)。

// X: does not exist, but this is a runtime condition
// so Serilog will not fail here.
Log.Logger = new LoggerConfiguration()
.WriteTo.File("X:\\log.txt")
.CreateLogger();

这种策略可以防止部署环境中的暂时性问题导致原本有效的应用程序失败。

开发时不变性违规

在配置时,对于永远无法有效执行的代码(例如,违反 API 不变性的情况)会做出一定的容忍:

// Null is never acceptable as a filename, so
// Seriog will throw ArgumentNullException here.
Log.Logger = new LoggerConfiguration()
.WriteTo.File(null)
.CreateLogger();

这一决定基于两个原因:

这些错误不太可能通过开发者的工作站或测试环境,因为日志记录配置发生在启动时,并且应该总是以相同的方式失败。

允许无效值或静默忽略它们会导致意外行为,这很难调试,并使库的正确配置更加困难。

如果您愿意,可以将日志记录配置代码包装在 try/catch 结构中,以避免异常传播,但不推荐这样做。

接收器作者: 实现这一点的责任在于接收器的实现本身,因此需要明确考虑/处理。

2、写入日志事件

事件分阶段写入日志记录管道。首先调用记录器,然后构造事件,接下来对其进行丰富,应用过滤器,最后将其传递(“发出”)到配置的接收器。

调用记录器

ILogger 和静态 Log 类上的方法会静默忽略无效参数:

// Safely does nothing
Log.Warning(null);

这样做是因为在执行频率较低的代码路径中的日志记录语句可能不会被测试,因此不应在运行时失败。

构造日志事件

当构造日志事件时,Serilog 可能会反射任何解构对象的属性。

如果这些属性抛出异常,Serilog 会捕获错误,写入 SelfLog,并在解构对象中包含错误信息而不是属性值。

关于类型加载的说明

如果一个应用程序在没有所需依赖项的情况下部署,加载器可能会无法找到/构造有效类型。这是一个主要的应用程序配置错误,可能在解构过程中或稍后,例如在 JIT 阶段显现出来。这种情况非常罕见。在这种情况下,Serilog 不会做任何事情,允许错误传播。

装饰器

装饰器向日志事件添加属性。装饰器可能会抛出异常:Serilog 会捕获这些异常并写入 SelfLog。

装饰器作者: Serilog 自身实现了这一策略,装饰器在意外失败时应抛出异常(尽管出于性能考虑,避免这种情况是明智的)。

过滤器

过滤器决定哪些事件会被传递到日志记录管道中。过滤器不会抛出异常,而是写入 SelfLog:

// No events will be carried through this pipeline, but no
// errors will be thrown.
Log.Logger = new LoggerConfiguration()
.Filter.ByExcluding(e => { throw new Exception(); })
.WriteTo.ColoredConsole()
.CreateLogger();

过滤器作者: 如果过滤器意外抛出异常,这被视为一个错误——这对性能和功能的影响是显著的。

发出到接收器

Serilog 捕获并将接收器引发的任何异常写入 SelfLog。通常情况下,这些异常是正常使用 Serilog 时发生的绝大多数异常。

接收器作者: 接收器在失败时应抛出异常。Serilog 将一致地捕获和处理这些异常。

关于不可捕获的异常的说明

需要注意的是,仍然存在一类不可捕获的异常,Serilog 被迫传播这些异常,例如 StackOverflowException 等。

3、异步/批处理网络操作

许多 Serilog 接收器使用相同的基础 PeriodicBatchingSink 架构。这些接收器(例如批处理的 Azure 表存储接收器、CouchDB 接收器、RavenDB 接收器和 Seq 接收器(在非持久模式下))会缓存日志事件,从而减少将日志数据传输到远程主机所需的网络往返次数。

Log.Logger = new LoggerConfiguration()
.WriteTo.CouchDB("api/missing")
.CreateLogger()

这些接收器在写入事件时不会失败,但可能会在后台异步发送批次时失败。当批次发送失败时,详细信息将写入 SelfLog。

正在发送的批次将保留在内存中,并会以逐渐增加的时间间隔重试,时间间隔从 5 秒逐步增加到 10 分钟。增加的时间间隔可以保护接收器,在经历一段停机后重新上线时,避免连接洪水。

如果经过 4 次尝试仍无法发送批次,该批次将被丢弃并尝试新的批次。这可以防止接收器拒绝的“坏”事件堵塞日志记录器。后续的成功将允许其他批次正常传输。

如果再有两次尝试失败(总共 6 次失败,通常在 10 分钟左右),等待的日志事件的整个缓冲区将被丢弃。这可以防止在日志事件长时间无法送达时出现内存不足错误。

如果连接仍然中断,缓冲区将每 10 分钟刷新一次,直到重新建立连接。

接收器作者: 通过从 PeriodicBatchingSink 派生,可以默认提供此行为。如果需要不同的行为,则需要实现自定义的 ILogEventSink。

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

Serilog文档翻译系列(八) - 记录器的生命周期、可靠性的更多相关文章

  1. 【微信小程序开发•系列文章六】生命周期和路由

    这篇文章理论的知识比较多一些,都是个人观点,描述有失妥当的地方希望读者指出. [微信小程序开发•系列文章一]入门 [微信小程序开发•系列文章二]视图层 [微信小程序开发•系列文章三]数据层 [微信小程 ...

  2. Unity3D实践系列04, 脚本的生命周期

    Unity3D脚本生命周期是指从脚本的最初唤醒到脚本最终销毁的整个过程.生命周期的各个方法被封装到了MonoBehaviour类中.具体来说如下: 1.In Editor Mode 编辑模式 当在编辑 ...

  3. 死磕 java线程系列之线程的生命周期

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的. 常见的错 ...

  4. Spring学习记录(八)---Bean的生命周期

    之前说过,在调用下面时,就创建了容器和对象 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml&quo ...

  5. Vue系列之 => 钩子函数生命周期

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 八、spring生命周期之BeanPostProcessor

    BeanPostProcessor我们一般称为Bean的后置处理器,它与我们前面介绍的InitialingBean.init-method等一样,都是在bean的初始化时被调用,具体的用法我们在举例中 ...

  7. Vue系列(二):发送Ajax、JSONP请求、Vue生命周期及实例属性和方法、自定义指令与过渡

    上一篇:Vue系列(一):简介.起步.常用指令.事件和属性.模板.过滤器 一. 发送AJAX请求 1. 简介 vue本身不支持发送AJAX请求,需要使用vue-resource.axios等插件实现 ...

  8. Android Studio 单刷《第一行代码》系列 06 —— Fragment 生命周期

    前情提要(Previously) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Andr ...

  9. iOS系列 基础篇 03 探究应用生命周期

    iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本 ...

  10. iOS系列 基础篇 04 探究视图生命周期

    iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...

随机推荐

  1. 【Java】【常用类】Calendar 日历类

    Calendar 日历类,我居然念错发音,来,好好看下音标  ['kælɪndə]  卡琳达 public class DateTest { public static void main(Strin ...

  2. 【SpringBoot】01 快速上手

    环境搭建: JDK8 + IDEA 2018 + SpringBoot + Maven 3.0 + 创建Boot项目 2020.6.1更新补充: 最近才发现SpringBoot用IDEA构建项目会发生 ...

  3. 【PC-Game】世嘉拉力:进化

    SegaRally:Revo游戏本体资源: 游侠网115盘 + 详细介绍 https://game.ali213.net/forum.php?mod=viewthread&tid=409661 ...

  4. OpenCV计算机视觉学习(16)——仿射变换学习笔记

    如果需要其他图像处理的文章及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractic ...

  5. 神州笔记本 win11 节能模式 供电不足 自动关机

    刚刚买了一个神州笔记本没几天,用着用着就出现问题了. 本人使用电脑有个极为不好的习惯,那就是会一次性打开特别多的应用,然后不关,一直留着,这个习惯虽然不好但也是一直没有啥问题的,不过最近换了个新的笔记 ...

  6. SeaTunnel DB2 Source Connector 使用文档(含详细操作步骤)

    DB2是IBM的一款关系型数据库管理系统,JDBC DB2 Source Connector是一个用于通过JDBC读取外部数据源数据的连接器.Apache SeaTunnel如何支持JDBC DB2 ...

  7. Kotlin 循环与函数详解:高效编程指南

    Kotlin 循环 当您处理数组时,经常需要遍历所有元素. 要遍历数组元素,请使用 for 循环和 in 操作符: 示例 输出 cars 数组中的所有元素: val cars = arrayOf(&q ...

  8. Java——N以内累加求和

    2024/07/15 1.题目 2.错误 3.分析 4.答案 1.题目 2.错误 import java.util.Scanner; public class Main { public static ...

  9. zabbix网络拓扑图介绍

    "zabbix network map"可以简单的理解为动态网络拓扑图,可以针对业务来配置zabbix map,通过map可以了解应用的整体状况:服务器是否异常.网络是否有故障.应 ...

  10. Linux 挂载设备

    手动挂载 挂载: # 创建挂载目录 sudo mkdir -p /path/to/mount # 挂载 sudo mount /dev/sdX1 /path/to/mount # 确认挂载 df -h ...