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课堂之个人信息接口开发 《十三》

    根据token从查询个人信息接口开发 直接解密token,获取个人信息 通过token解密查询数据库获取个人信息 UserController.java package net.ybclass.onl ...

  2. MDI子窗口+事件与委托的一个例程

    1首先,新建WinForm的.NetFramWork的工程并添加2个Form: 2设置 Form1为MDI主窗口: [属性]-- 将以上属性改为 True; 另外,也可以采用代码形式: this.Is ...

  3. redis基本数据结构-字符串

    reids字符串数据结构相关命令    序号 命令 命令实例 意义    1 set key value set bar 1 设置key为bar的值为"1"   2  incr k ...

  4. [oeasy]python0093_电子游戏起源_视频游戏_达特茅斯_Basic_家酿俱乐部

    编码进化 回忆上次内容 Ed Robert 的 创业之路 从 售卖 diy 组装配件 到进军 计算器市场 最后 发布 牛郎星8800 intel 8080 的出现 让 人人都有 自己的 个人电脑 Bi ...

  5. [oeasy]python0031_挂起进程_恢复进程_进程切换

    ​ 查看进程 回忆上次内容 上次修改了 $PATH 路径 把当前用户shiyanlou的宿主文件夹 ~ 添加到 $PATH 中 这样 sleep.py 就可以被找到 于是就可以被执行了 还可以把配置 ...

  6. [rCore学习笔记 05]第0章作业题

    作业1 略. 作业2 C语言程序 gcc编译 gcc -o main main.c 编译报错 成功产生异常 main.c: In function 'main': main.c:5:26: warni ...

  7. vue 路由缓存 keep-alive include和exclude无效

    <keep-alive :include="keepAliveData"> <router-view v-if="isShowRouter" ...

  8. hadoop hive hbase flume sqoop基本操作

    top 里的id为cpu空闲度 如果wa为99.8就是负担太重.得停掉一些任务 cat /proc/cpuinfo 查看cpu信息 cat /proc/meminfo 查看内存信息 hadoop基础操 ...

  9. ambari+ bigtop 编译、打包、部署步骤总览

    1 ambari + bigtop 构建大数据基础平台 1.1 参考: 1.2 参考 amabri bigtop 打包部署 2 ambari+bigtop编译.打包.部署 2.0 基础环境准备 2.1 ...

  10. Jmeter函数助手24-longSum

    longSum函数可用于计算两个或多个长值的和.intSum函数参数值的范围在-2147483648到2147483647之间,而longSum函数的参数值范围比intSum的大. First lon ...