Serilog文档翻译系列(四) - 结构化数据

news/2024/11/14 15:02:01/文章来源:https://www.cnblogs.com/hugogoos/p/18398988

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/792833.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#自定义控件—指示灯

C#用户控件之指示灯 在体现通讯状态、运行状态等用一个靓眼的指示灯如何做?思路(GDI)外环用笔绘制(Pen),内圆用画刷(SolidBrush);两个方法(用笔画圆,用画刷填充圆的内部):绘制边界RectangleF定义的椭圆/圆DrawEllipse(Pen pen,RectangleF rect)填充RectangleF定义边…

从0认识竞品分析(附实战分析抖音)

什么是竞品分析?顾名思义,是对竞争对手的产品进行比较分析的过程,一种带有主观性的横向分析过程;通过对多个产品的整体架构、功能、商业模式、产品策略等多维度的横向对比分析,从而获得目的性的结论。那如何分析呢?我们这里按照下面几个点来一一展开:**明确目的,行业分…

sql注入(极客大挑战2019EasySQL1)

题目链接我们输入 http://643dcead-c254-412c-a4fe-5787862bbf9e.node5.buuoj.cn:81/check.php?username=admin and password=13123响应为如下,提示我们输入password,看似url中查询了password,但是因为这是一个字符型注入,后台url转为 SELECT * FROM users WHERE username…

ATTCK红队评估(红日靶场1)

前言博主小白一个,各位大佬勿喷,前前后后,学了挺久的,学了之后又忘了,因此来打红日靶场1巩固知识。文章写的不是很好,缺少很多细节,博主也是内网小白,很多都不懂,互相学习 靶机介绍​本靶机环境是红日团队开源的一个红队实战测试环境,靶机下载地址如下:​http://vul…

地理信息科学在考古学中的应用:GIS与遥感技术的时空穿梭之旅

在历史的长河中,每一片土地都承载着文明的记忆。随着科技的进步,地理信息科学(GIS)与遥感技术正逐渐揭开古老秘密的面纱,让沉睡千年的历史遗迹重新焕发光彩。今天,就让我们踏上一场穿越时空的旅程,探索GIS和遥感技术如何在考古发掘和研究中扮演着至关重要的角色。 GIS:…

【漏洞分析】Penpie 攻击事件:重入攻击构造奖励金额

背景信息 2024 年 9月 3日,Penpie 合约遭受重入攻击,攻击者在重入阶段向合约添加流动性来冒充奖励金额,从而获取合约内原有的奖励代币。资产损失高达 2734 万美元。 2024 年 5月,Penpie 平台新增了推出了无需许可的资产池功能,即允许 Pendle 上的用户可以在该平台上自建任…

8.30域横向-PTHPTKPTT票据传递

知识点 Kerberos协议具体工作方法,在域中: 客户机将明文密码进行NTLM哈希,然后和时间戳一起加密(使用krbtgt密码hash作为密钥),发送给kdc(域控),kdc对用户进行检测,成功之后创建TGT(Ticket-Granting Ticket)。 将TGT进行加密签名返回给客户机器,只有域用户krbtgt才能…

系统设计思想之Domain驱动

一、DDD从放弃到入门 希望了解一套微服务框架的;希望学习到新技术的;开发的系统不复杂,模块少而独立的;当前自己设计的架构已满足拓展性,可复用性,技术与业务复杂度已分离的;这几类人群不是DDD的目标人群,建议尽早放弃,学习领域驱动设计能得到的收获概括起来大致如…

逻辑回归模型

核心:线性回归+sigmoid映射。 一、概述逻辑回归模型(Logistic Regression,LR),由名称上来看,似乎是一个专门用于解决回归问题的模型,事实上,该模型更多地用于解决分类问题,尤其是二分类问题。这并不矛盾,因为逻辑回归直接输出的是一个连续值,我们将其按值的大小进行切…

Winform下的画板

1. Winform如何实现简单绘图如果想要自己画一个圆,矩形或者其他图形,可以使用控件或窗体自带的Paint事件,在事件中引用Graphics对象; 也可以使用某个窗体或者控件的CreateGraphics方法 需要引用using System.Drawing.Drawing2D;(要画3D就用DirectX)2. 使用Form1窗体Paint…

STM32学习笔记——Keil uVision5建项目

新建文件夹——用于存放工程及工程管理 新建文件夹用于存放整个工程打开“stm32-project”文件夹,新建一些文件夹用于工程源代码的分类这些文件夹都是自己建的用于不同类型代码存放,文件夹个数,命名都因人而异。(后续所有文件放在“stm32-project”中也行,不嫌乱的话) Ha…

Jenkins - 触发器

触发方式 jenkins自带的job触发方式Generic Webhook Trigger插件 在需要外界其他系统触发Jenkins任务的场景,通常使用Generic Webhook Trigger插件来配置 Jenkins 触发器 Generic Webhook Trigger 插件允许使用 Webhook将外部系统与 Jenkins 集成。 通过配置 Webhook,在特定事…