日志事件通过 Log 静态类或 ILogger 接口上的方法写入接收器。下面的示例将使用 Log 以便语法简洁,但下面显示的方法同样可用于接口。

Log.Warning("Disk quota {Quota} MB exceeded by {User}", quota, user);

通过此日志方法创建的警告事件将具有两个相关属性,Quota 和 User。假设 quota 是一个整数,user 是一个字符串,呈现的消息可能如下所示。

Disk quota 1024 MB exceeded by "nblumhardt"

(Serilog 使用双引号渲染字符串值,以更清晰地指示其底层数据类型,并使属性值从周围的消息文本中脱颖而出。)

01、消息模板语法

上述字符串 “Disk quota {Quota} exceeded by {User}” 是一个 Serilog 消息模板。消息模板是标准 .NET 格式字符串的超集,因此任何适用于 string.Format() 的格式字符串也会被 Serilog 正确处理。

  • 属性名称用 { 和 } 括起来书写。
  • 属性名称必须是有效的 C# 标识符,例如 FooBar,但不能是 Foo.Bar 或 Foo-Bar。
  • 括号可以通过重复书写来转义,例如 {{ 将被渲染为 {。
  • 使用数字属性名称的格式,如 {0} 和 {1},将通过将属性名称视为索引来与日志方法的参数匹配;这与 string.Format() 的行为相同。
  • 如果任何属性名称是非数字,则所有属性名称将从左到右与日志方法的参数进行匹配。
  • 属性名称可以带有可选的运算符前缀 @ 或 $,以控制属性的序列化方式。
  • 属性名称可以带有可选的格式后缀,例如 :000,以控制属性的渲染方式;这些格式字符串的行为与 string.Format() 语法中的对应部分完全相同。

02、消息模板推荐

流畅风格指南:好的 Serilog 事件使用属性名称作为消息内容,如上面的用户示例。这提高了可读性,并使事件更简洁。

句子与片段:日志事件消息是片段,而不是句子;为了与其他使用 Serilog 的库保持一致,尽量避免使用句末的句号。

模板与消息:Serilog 事件关联的是消息模板,而不是消息。内部,Serilog 会解析并缓存每个模板(直到固定大小限制)。将日志方法的字符串参数视为消息,如下例所示,会降低性能并消耗缓存内存。

//不推荐
Log.Information("The time is " + DateTime.Now);

相反,始终使用模板属性在消息中包含变量

// 推荐
Log.Information("The time is {Now}", DateTime.Now);

属性命名:属性名称应使用 PascalCase,以保持与 Serilog 生态系统中其他代码和库的一致性。

03、日志事件级别

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

  • 详细信息(Verbose) - 跟踪信息和调试细节;通常仅在特殊情况下开启。
  • 调试(Debug) - 内部控制流和诊断状态转储,以便于定位已知问题。
  • 信息(Information) - 对外部观察者有意义或相关的事件;默认启用的最低日志级别。
  • 警告(Warning) - 可能问题或服务/功能下降的指示。
  • 错误(Error) - 指示应用程序或连接系统中的失败。
  • 致命(Fatal) - 导致应用程序完全失败的严重错误。

1、信息级别的作用

信息级别与其他指定级别不同-它没有特定的语义,许多方面上表达了其他级别的缺失。

由于 Serilog 允许对应用程序的事件流进行处理或分析,信息级别可以视为事件的同义词。也就是说,大多数有趣的应用程序事件数据应记录在此级别。

2、级别检测

在大多数情况下,应用程序应该在不检查当前日志级别的情况下记录事件。级别检查的开销非常小,而调用禁用的日志记录方法的开销也很低。

在少数性能敏感的情况下,推荐的级别检测模式是将级别检测的结果存储在一个字段中,例如:

readonly bool _isDebug = Log.IsEnabled(LogEventLevel.Debug);

可以在写入日志事件之前高效地检查 _isDebug 字段:

if (_isDebug) Log.Debug("Someone is stuck debugging...");

3、动态级别

许多大型或分布式应用需要在相对限制的日志级别下运行,例如信息级(我更倾向于这种)或警告级,并仅在检测到问题时将日志级别提高到调试级或详细级,以便收集更多数据的开销是合理的。

如果应用需要动态切换日志级别,第一步是在配置日志记录器时创建一个 LoggingLevelSwitch 的实例:

var levelSwitch = new LoggingLevelSwitch();

该对象默认将当前最低级别设置为信息级,因此为了使日志记录更为严格,可以提前设置其最低级别:

levelSwitch.MinimumLevel = LogEventLevel.Warning;

在配置日志记录器时,使用 MinimumLevel.ControlledBy() 提供该开关:

var log = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.WriteTo.ColoredConsole()
.CreateLogger();

现在,写入日志记录器的事件将根据开关的 MinimumLevel 属性进行过滤。

要在运行时调整日志级别,例如响应通过网络发送的命令,可以更改该属性:

levelSwitch.MinimumLevel = LogEventLevel.Verbose;
log.Verbose("This will now be logged");

04、源上下文

Serilog 和大多数 .NET 日志框架一样,允许事件带上其来源标签,通常是写入这些事件的类的名称:

var myLog = Log.ForContext<MyClass>();
myLog.Information("Hello!");

写入的事件将包含一个属性 SourceContext,其值为 "MyNamespace.MyClass",可以用来过滤噪音事件或选择性地将其写入特定的接收器。

并非所有附加到事件的属性都需要在消息模板或输出格式中表示;所有属性都存储在底层 LogEvent 对象的字典中。

有关过滤器和日志记录拓扑的更多信息,请参阅《Serilog文档翻译系列(三) - 基础配置》知识。

05、关联

正如 ForContext() 会将日志事件标记为写入它们的类,ForContext() 的其他重载允许日志事件用标识符进行标记,这些标识符随后可以支持与该标识符关联的事件的关联。

var job = GetNextJob();
var jobLog = Log.ForContext("JobId", job.Id);
jobLog.Information("Running a new job");
job.Run();
jobLog.Information("Finished");

在这里,两个日志事件都将携带 JobId 属性,其中包含作业标识符。

提示:当记录到使用文本格式的接收器时,例如 Serilog.Sinks.Console,可以在输出模板中包含 {Properties} 来打印出所有未包含的上下文属性。

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

Serilog文档翻译系列(五) - 编写日志事件的更多相关文章

  1. MySQL系列(五)--二进制日志对主从复制的影响

    MySQL复制是基于主库上的二进制日志来完成,复制是异步的,可能存在延迟 MySQL日志分为: 1.服务层日志:二进制日志.通用日志.慢查日志 2.存储引擎层日志:innodb中重做日志和回滚日志 二 ...

  2. C#微信公众号开发系列教程五(接收事件推送与消息排重)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  3. 普冉PY32系列(五) 使用JLink RTT代替串口输出日志

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...

  4. Netty4.x中文教程系列(五)编解码器Codec

    Netty4.x中文教程系列(五)编解码器Codec 上一篇文章详细解释了ChannelHandler的相关构架设计,版本和设计逻辑变更等等. 这篇文章主要在于讲述Handler里面的Codec,也就 ...

  5. JVM系列五:JVM监测&工具

    JVM系列五:JVM监测&工具[整理中]  http://www.cnblogs.com/redcreen/archive/2011/05/09/2040977.html 前几篇篇文章介绍了介 ...

  6. WCF开发实战系列五:创建WCF客户端程序

    WCF开发实战系列五:创建WCF客户端程序 (原创:灰灰虫的家http://hi.baidu.com/grayworm) 在前面的三篇文章中我们分别介绍了WCF服务的三种载体:IIS.Self-Hos ...

  7. WCF编程系列(五)元数据

    WCF编程系列(五)元数据   示例一中我们使用了scvutil命令自动生成了服务的客户端代理类: svcutil http://localhost:8000/?wsdl /o:FirstServic ...

  8. VSTO之旅系列(五):创建Outlook解决方案

    原文:VSTO之旅系列(五):创建Outlook解决方案 本专题概要 引言 Outlook对象模型 自定义Outlook窗体 小结 一.引言 在上一个专题中,为大家简单介绍了下如何创建Word解决方案 ...

  9. Orchard core 中文文档翻译系列

    本系列翻译顺序完全参照 官方顺序 原文地址:https://orchardcore.readthedocs.io/en/latest/ Orchard Core 中文文档翻译(一)关于Orchard ...

  10. Hexo系列(五) 撰写文章

    在利用 Hexo 框架搭建一个属于我们自己的博客网站后,下面我们就来谈谈怎样在网站上书写我们的第一篇博客吧 一.创建文章 在站点文件夹中打开 git bash,输入如下命令创建文章,其中 title ...

随机推荐

  1. JavaScript '&&' 与 '||' 操作符

    "&&" 操作符 1.如果第一个操作数是对象,则返回第二操作数 var res = {} && "Hello";//Hello ...

  2. Javascript 转Date对象为字符串实现函数

    转Date对象为字符串实现函数 function formatDate(time, format = "Y-MM-dd HH:mm:ss") { /** 格式化字符说明 Y 年 四 ...

  3. 微服务集成springsecurity实现认证

    module:auth 1.添加依赖:spring-cloud-starter-security与spring-cloud-starter-oauth2 2.配置WebSecurityConfig:注 ...

  4. HDP 源码集

    HDP 各个组件的源码(含历史各个版本) 分支 组件 标签 最后发版时间 地址 hadoop 2256 2020-12-21 17:44 https://gitee.com/piaolingzxh/h ...

  5. Jmeter函数助手35-property

    property函数用于获取jmeter属性值. 属性名称:填入jmeter的属性名称 存储结果的变量名(可选) 默认值:缺省值,当获取属性值为空时则返回该值 1.查看jmeter全局属性,测试计划右 ...

  6. 【Java】树状节点结构的数据

    数据库的菜单,权限表是具有多层级结构,有ID和PARENT_ID两个关键性的字段 通过PARENT_ID和ID相等构建层级结构: 然后需要在Java中构建出层级的数据结构,然后输出成JSON返回给前端 ...

  7. python性能分析器:cProfile

    代码: (1) import cProfile import re cProfile.run('re.compile("foo|bar")') 运行结果: (2) import c ...

  8. TensorFlow和pytorch中的pin_memory和non_blocking设置是做什么的,又是否有用???(续2)

    接前文: TensorFlow和pytorch中的pin_memory和non_blocking设置是做什么的,又是否有用??? TensorFlow和pytorch中的pin_memory和non_ ...

  9. Java如何防御XSS攻击?

    Q1.什么是XSS攻击? 定义很多,这里我找一个比较详细的解释 https://www.cnblogs.com/csnd/p/11807592.html Q2.为什么会有XSS攻击 也看上面的链接 Q ...

  10. [学习笔记] 阶 & 原根 - 数论

    较为冷门(?)的数论知识,但在解决一些特殊问题上有着重要的作用. 整数的阶 根据欧拉定理有正整数 \(n\) 和一个与 \(n\) 互素的整数 \(a\),那么有 $a^{\phi(n)} \equi ...