Serilog 是一种序列化器。在许多情况下,它具有良好的默认行为,能够满足其目的,但有时也需要指示 Serilog 如何存储附加到日志事件上的属性。

Serilog 使用一些不寻常的术语来指代 .NET 对象如何映射到其内部(与接收器无关的)属性表示。这些术语的详细解释如下,所以如果你打算阅读整页内容,可以跳过这一部分。

  • 字符串化(Stringification) 是指获取一个提供.NET 属性,并调用其 ToString() 方法,以便到达接收器的表示是一个简单的字符串。

  • 解构(Destructuring) 是指将复杂的 .NET 对象转换为结构的过程,这些结构可能会被表示为 JSON 对象或 XML 块。

  • 标量(Scalars) 是指可以表示为原子值的 .NET 类型;大多数值类型如 int 都符合这个描述,但一些引用类型如 Uri 和 string 也符合。

01、为什么需要控制表示方式?

记录对象到日志的方式可能有很多种。大多数类型可以很好地表示为字符串或简单值,但有些则更适合记录为集合,还有些则适合记录为具有命名属性的结构体。

日志事件属性的存储表示方式对日志的大小以及获取这些数据所需的内存和处理开销有很大影响。

考虑到这一点,我们来看看如何在简单情况下配置 Serilog。

02、默认行为

当在日志事件中指定属性时,Serilog 会尽力确定正确的表示方式。

简单的标量值

var count = 456;
Log.Information("Retrieved {Count} records", count);

在这种情况下,Count 属性的存储方式几乎没有歧义。作为一个简单的整数值,Serilog 会选择这种表示方式。

{ "Count": 456 }

这些示例使用 JSON,但相同的原则也适用于其他格式。

开箱即用,Serilog 识别以下列表作为基本标量类型,无论是否应用了其他策略:

  • 布尔值 - bool

  • 数值 - byte, short, ushort, int, uint, long, ulong, float, double, decimal

  • 字符串 - string, byte[]

  • 时间 - DateTime, DateTimeOffset, TimeSpan

  • 其他 - Guid, Uri

  • 可空类型 - 上述类型的可空版本

集合

如果作为属性传递的对象是IEnumerable,Serilog会将该属性视为集合。

var fruit = new[] { "Apple", "Pear", "Orange" };
Log.Information("In my bowl I have {Fruit}", fruit);
```对应的JSON包括一个数组。 ```csharp
{ "Fruit": ["Apple", "Pear", "Orange"] }

Serilog 之所以这样选择,是因为大多数可枚举类型关注的是其元素,而作为结构或字符串表示不佳。

Serilog还识别Dictionary<TKey,TValue>,只要键类型是上面列出的标量类型之一。

var fruit = new Dictionary<string,int> {{ "Apple", 1}, { "Pear", 5 }};
Log.Information("In my bowl I have {Fruit}", fruit);

支持字典的格式器可以将属性记录为字典。

{ "Fruit": { "Apple": 1, "Pear": 5 }}

IDictionary<TKey,TValue> - 实现字典接口的对象不会被序列化为字典。首先,因为在.NET中检查泛型接口兼容性效率较低,其次,一个对象可能实现多个泛型字典接口,从而产生歧义。

对象

除了上述特殊处理的类型之外,Serilog 很难智能地选择数据的渲染和持久化方式。未明确用于序列化的对象往往序列化效果很差。

SqlConnection conn = ...;
Log.Information("Connected to {Connection}", conn);

(哎呀!如何序列化一个 SqlConnection 对象?)

当 Serilog 无法识别该类型且未指定操作符(见下文)时,对象将使用 ToString() 方法进行渲染。

03、保留对象结构

在许多情况下,如果可能的话,将日志事件属性序列化为结构化对象是有意义的。数据传输对象(DTOs)、消息、事件和模型通常最好通过将其分解为具有值的属性来进行日志记录。

为此,Serilog 提供了 @ 解构操作符。

var sensorInput = new { Latitude = 25, Longitude = 134 };
Log.Information("Processing {@SensorInput}", sensorInput);

(“解构”一词是从各种编程语言中借用的;它是一种用于从结构化数据中提取值的模式匹配风格。目前,Serilog 中的用法仅与该术语在概念上相关,但未来对该运算符的扩展可能会更准确地匹配其更广泛的定义。)

自定义存储的数据

通常,对复杂对象的只有部分属性是感兴趣的。要自定义 Serilog 如何持久化解构的复杂类型,可以在 LoggerConfiguration 上使用 Destructure 配置对象:

Log.Logger = new LoggerConfiguration()
.Destructure.ByTransforming<HttpRequest>(
r => new { RawUrl = r.RawUrl, Method = r.Method })
.WriteTo...

这个示例将HttpRequest类型的对象转换为仅保留RawUrl和Method属性的新对象。可以使用多种不同的解构策略,也可以通过实现 IDestructuringPolicy 创建自定义策略。

注意:提供给 Destructure.ByTransforming() 的函数必须返回与传入类型不同的类型,否则会递归调用。可以使用自定义的 IDestructuringPolicy 来实现条件转换。

操作符与格式

虽然操作符和格式都影响属性的表示方式,但它们的作用是不同的。操作符在捕获属性时被应用,用于以某种方式保留或结构化数据。而格式则仅在将属性显示为文本时使用,不会影响序列化的表示。

格式化集合和结构

当为复杂属性指定格式字符串时,它们通常会被忽略。只有可枚举类型会考虑格式字符串,并在显示时将其传递给元素。

04、强制字符串化

有时,日志记录的对象类型可能不完全确定,或者可能以不希望在日志事件中保留的方式变化。在这些情况下,$ 字符串化操作符将把属性值转换为字符串,然后再进行其他处理,无论其类型或实现的接口是什么。

var unknown = new[] { 1, 2, 3 }
Log.Information("Received {$Data}", unknown);

尽管 unknown 是一个枚举类型,但它被捕获并以字符串形式呈现。

Received "System.Int32[]"

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

Serilog文档翻译系列(四) - 结构化数据的更多相关文章

  1. Solr系列四:Solr(solrj 、索引API 、 结构化数据导入)

    一.SolrJ介绍 1. SolrJ是什么? Solr提供的用于JAVA应用中访问solr服务API的客户端jar.在我们的应用中引入solrj: <dependency> <gro ...

  2. (四)DIH导入结构化数据

    (四)DIH导入结构化数据 目前大多数的应用程序将数据存储在关系数据库(如oracle.sql server .mysql等).xml文件中.对这样的数据进行搜索是很常见的应用.所谓的DataImpo ...

  3. ElasticSearch 2 (13) - 深入搜索系列之结构化搜索

    ElasticSearch 2 (13) - 深入搜索系列之结构化搜索 摘要 结构化查询指的是查询那些具有内在结构的数据,比如日期.时间.数字都是结构化的.它们都有精确的格式,我们可以对这些数据进行逻 ...

  4. WordPress插件--WP BaiDu Submit结构化数据插件又快又全的向百度提交网页

    一.WP BaiDu Submit 简介 WP BaiDu Submit帮助具有百度站长平台链接提交权限的用户自动提交最新文章,以保证新链接可以及时被百度收录. 安装WP BaiDu Submit后, ...

  5. 【阿里云产品公测】结构化数据服务OTS之JavaSDK初体验

    [阿里云产品公测]结构化数据服务OTS之JavaSDK初体验 作者:阿里云用户蓝色之鹰 一.OTS简单介绍 OTS 是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存储和实 ...

  6. Python爬虫(九)_非结构化数据与结构化数据

    爬虫的一个重要步骤就是页面解析与数据提取.更多内容请参考:Python学习指南 页面解析与数据提取 实际上爬虫一共就四个主要步骤: 定(要知道你准备在哪个范围或者网站去搜索) 爬(将所有的网站的内容全 ...

  7. TensorFlow从1到2(六)结构化数据预处理和心脏病预测

    结构化数据的预处理 前面所展示的一些示例已经很让人兴奋.但从总体看,数据类型还是比较单一的,比如图片,比如文本. 这个单一并非指数据的类型单一,而是指数据组成的每一部分,在模型中对于结果预测的影响基本 ...

  8. Bigtable:一个分布式的结构化数据存储系统

    Bigtable:一个分布式的结构化数据存储系统 摘要 Bigtable是一个管理结构化数据的分布式存储系统,它被设计用来处理海量数据:分布在数千台通用服务器上的PB级的数据.Google的很多项目将 ...

  9. [转] Protobuf高效结构化数据存储格式

    从公司的项目源码中看到了这个东西,觉得挺好用的,写篇博客做下小总结.下面的操作以C++为编程语言,protoc的版本为libprotoc 3.2.0. 一.Protobuf? 1. 是什么?  Goo ...

  10. RocketMQ Schema——让消息成为流动的结构化数据

    本文作者:许奕斌,阿里云智能高级研发工程师. Why we need schema RocketMQ 目前对于消息体没有任何数据格式的约束,可以是 JSON ,可以是对象 toString ,也可以只 ...

随机推荐

  1. yb课堂 实战之Mybatis打通Mysql数据库 《二》

    配置mybatis连接Mysql数据库 server.port=8081 # ========================数据库相关配置===================== spring.d ...

  2. JVM学习笔记-如何在IDEA打印JVM的GC日志信息

    若要在Idea上打印JVM相应GC日志,其实只需在Run/Debug Configurations上进行设置即可. 拿<深入Java虚拟机>书中的3-7代码例子来演示,如 1 public ...

  3. 安卓app产品:应用分析工具

    这是我独立开发的一款工具类安卓app(名称:应用分析工具),其主要功能是:(Solo 社区投稿) 1.基础信息查看 - 可查看app的包名.签名.权限.版本信息.AndroidManifest.xml ...

  4. 推荐一款功能强大、界面优美的开源SSH跨平台终端软件WindTerm

    WindTerm是一款开源免费且功能强大的终端软件,相比 MobaXterm自带中文支持.无论是在Windows.macOS还是Linux操作系统上,WindTerm都能提供出色的性能和稳定性.Win ...

  5. 部分解决 | ocrmypdf对中文pdf进行ocr识别后存在多余空格

    1.问题 ocrmypdf安装采用的是在windows安装方法具体看 https://media.readthedocs.org/pdf/ocrmypdf/latest/ocrmypdf.pdf 由于 ...

  6. Memcache 与 Memcached 的区别

    Memcached 从0.2.0开始,要求PHP版本>=5.2.0,Memcache 要求PHP版本>=4.3. Memcached 最后发布时间为2018-12-24,Memcache ...

  7. LLM并行训练6-激活优化

    前置知识 Activation 激活指的是一些在fp时计算得到的临时tensor, 会用于bp时的计算. 如果能在fp计算后把临时tensor缓存下来就可以加速bp, 缺点在于某些激活会占用大量显存. ...

  8. 学习笔记--Java中的数据类型

    Java中的数据类型 /** * Java中的数据类型: * 程序当中有很多的数据,每一个数据拥有与之相关的类型. * * * 1. 数据类型的作用: * 不同类型的数据占用的空间大小不同,数据类型的 ...

  9. MySQL之DQL

    *****DQL -- 数据查询语言   查询不会修改数据库表记录! 一. 基本查询 1. 字段(列)控制 1) 查询所有列  SELECT * FROM 表名;  SELECT * FROM emp ...

  10. httpURLConnection 请求发起post请求

    常见请求头,在post请求之 前先了解一下,请求相关的基础 关于post 请求的方式比get  多了很多配置,其实大致一样,本想将get示例和post写在一起,这个博客功能有时有问题 一直在灰色的编辑 ...