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. 基于 TrueLicense 项目证书生成

    一.创建公钥私钥 1.首先要用 KeyTool 工具来生成私匙库:(-alias别名 -validity 3650 表示10年有效,这个时间不是License的过期时间) keytool -genke ...

  2. 【Vue】接口模块化处理

    在前端Vue项目中,接口会被统一放在一个目录中管理: 一个模块的所有接口放在一个JS文件中: 文件会导入封装好的请求方法,和动态绑定的接口地址 import request from '@/utils ...

  3. 【Tutorial C】01 概述

    历史 History 欢迎来到C语言的世界!C语言是一种强大的专业化编程语言,深受业余和专业编程人员的欢迎. 在学习之前先让我们了解和认识它! C语言的原型是A语言(ALGOL 60语言). 1963 ...

  4. 【DataBase】MySQL 28 流程控制

    一.分支结构 1.IF函数 语法: IF(表达式1, 表达式2, 表达式3) 类似三元运算符,表达式1返回True Or False True执行表达式2,False执行表达式3 IF实现多分枝结构 ...

  5. 个人17年购入的HP 暗影2pro笔记本开机掉电,电池无法充电,无法开机

    相关链接: https://www.cnblogs.com/devilmaycry812839668/p/15228316.html 机器问题: 1. 电池时而能充电时而不能充电,有时候使用7天后不能 ...

  6. (计算机类)人工智能方向会议的截止时间表 —— AI Conference Deadlines —— 会议投稿截止时间

    由 https://paperswithcode.com/ 提供的时间表. 做AI方向的research,经常需要关注的就是conference的deadline,之前往往都是需要手动的去挨个搜索,下 ...

  7. 深度解读KubeEdge架构设计与边缘AI实践探索

    摘要:解读业界首个云原生边缘计算框架KubeEdge的架构设计,如何实现边云协同AI,将AI能力无缝下沉至边缘,让AI赋能边侧各行各业,构建智能.高效.自治的边缘计算新时代,共同探索智能边缘的新篇章. ...

  8. 【模板】最近公共祖先:LCA算法

    LCA最近公共祖先 \[\begin{align} 要求 \ 给出一个树和他的根节点\text{root} \quad给出Q个询问 回答\text {LCA}(a,b) \end{align} \] ...

  9. springboot解析自定义yml

    springboot解析自定义yml 在实际项目开发中我们经常需要用到一些自定义配置,并且希望单独配置,方便维护,现在介绍下方式: 方式一手动加载 对于一些不变动的配置,写死在项目中维护,如下 然后在 ...

  10. OpenPCDet为KITTI数据集生成数据信息出现错误TypeError: load() missing 1 required positional argument: ‘Loader‘的解决方案

    OpenPCDet为KITTI数据集生成数据信息出现错误 TypeError: load() missing 1 required positional argument: 'Loader' 通过查阅 ...