结构化方法有两个基本的进步,如果没有(有时是极端的)额外的努力,就无法使用文本日志来模拟。
活动类型
当您使用log4net编写两个事件时,例如:
log.Debug("Disk quota {0} exceeded by user {1}", 100, "DTI-Matt");
log.Debug("Disk quota {0} exceeded by user {1}", 150, "nblumhardt");
这些将产生类似的文本:
Disk quota 100 exceeded by user DTI-Matt
Disk quota 150 exceeded by user nblumhardt
但是,就机器处理而言,它们只是两行不同的文本。
您可能希望找到所有“磁盘配额已超出”事件,但是like 'Disk quota%'
一旦另一个事件发生,查找事件的简单情况就会下降:
Disk quota 100 set for user DTI-Matt
文本记录会丢弃我们最初获得的有关事件源的信息,并且在读取日志时通常必须使用越来越复杂的匹配表达式来重新构造该信息。
相比之下,当您编写以下两个Serilog事件时:
log.Debug("Disk quota {Quota} exceeded by user {Username}", 100, "DTI-Matt");
log.Debug("Disk quota {Quota} exceeded by user {Username}", 150, "nblumhardt");
它们产生与log4net版本相似的文本输出,但是在后台,两个事件都携带了"Disk quota {Quota} exceeded by user {Username}"
消息模板。
使用适当的接收器,以后您可以编写查询where MessageTemplate = 'Disk quota {Quota} exceeded by user {Username}'
并确切获取超出磁盘配额的事件。
在每个日志事件中存储整个消息模板并不总是很方便,因此有些接收器会将消息模板的哈希值哈希成一个数字EventType
值(例如0x1234abcd
),或者,您可以在日志记录管道中添加一个扩展器以自己完成。
它比下面的下一个差异更加微妙,但是在处理大量日志时却具有强大的功能。
结构化数据
再次考虑两个有关磁盘空间使用情况的事件,使用文本日志使用来查询特定用户可能很容易like 'Disk quota' and like 'DTI-Matt'
。
但是,生产诊断并不总是那么简单。想象一下是否有必要查找超出磁盘配额低于125 MB的事件?
使用Serilog,可以在大多数接收器中使用以下变量来实现:
Quota < 125
从正则表达式构造这种查询是可能的,但是它很快就很累人,通常最终只能作为最后的手段。
现在添加一个事件类型:
Quota < 125 and EventType = 0x1234abcd
您开始在这里看到这些功能如何以直接的方式组合在一起,以使带有日志的生产调试感觉像是一流的开发活动。
另一个好处是,也许不是很容易预防,但是一旦将生产调试从regex黑客工具中解放出来,开发人员便开始更加珍惜日志,并在编写日志时更加谨慎。更好的日志->更好质量的应用程序->更加幸福。