在SLF4J/Logback中使用标记的最佳实践

157
我们的项目现在已经使用SLF4J+Logback组合相当一段时间,并且非常满意,但我们的日志记录策略非常简单,只是使用基于类的直接记录器,没有像MDC或Markers这样的花哨功能。
我想知道的是社区中是否有人实际上使用这些功能以及如何使用它们来改进日志记录/过滤。

我特别想知道在何处、为什么以及如何使用标记[1]进行日志记录。它们似乎是添加语义上下文到日志记录中的很棒的功能 - 例如,虽然一个类可能处理多个关注点,但可以使用任务/关注点特定的标记来区分日志语句。
创建和使用标记的最佳实践、约定或策略是什么?
更新:我猜我真正需要的不是如何使用标记,而是如何使用标记部分-是否有一些好的命名标记的最佳实践(例如使用带空格的纯文本或破折号/下划线/标点符号分隔的关键字样式名称),是否应该有一些“标准名称”的池,基于业务功能对命名的东西。我可能自己可以弄清楚这些问题,但如果我想系统地使用这些功能并将其介绍给一组开发人员,就有必要拥有一些规范化的指南...
[1] - 通过询问如何使用标记,我并不是真正在问如何使用API(它真的非常简单)-我更确切地指的是在使用标记进行日志记录时设置日志记录的一般级别。
5个回答

117

首先,就像@darioo所说的那样:

  • MDC用于将多个事件与少数“实体”关联起来
  • 标记(Markers)用于过滤“特殊”事件,使其与通常情况下的事件区分开来

因此你的假设是想使用MDC。标记是用于突出显示“特殊”事件- 过滤,而不是“切片”。例如,您可能会基于特定用户进行切片,但基于任何意外异常进行过滤。在这种情况下,您需要创建一个User MDC维度和一个UnexpectedException Marker。


但是这显然没有回答你心中的问题。你“更倾向于谈一谈如何在日志记录周围使用标记(Markers)设置日志输出等级。” 那么让我们来解决这个问题:

MDC是用于“切片和切块”,而标记(Markers)是用于“过滤”的。 这些活动在测试和生产中都要进行。因此,当测试和生产到来时,您需要决定哪些维度可能对切片日志数据有用,并且哪些情况可能对其进行过滤。 每个维度都有一个MDC维度。每种情况都有一个标记(Marker)。就那么简单。

开发人员无需在此做出任何决策。 应该有一个人或团队,在设计时决定要支持哪种切片、切块和过滤。这应该基于想象可能会被要求执行什么样的分析任务。

同一人或团队应该决定命名约定。 完全是任意的。选择美观,自描述(最重要),并且足够特定以不太可能与后来的添加产生冲突的内容。连字符(-)与下划线(_)之间的区别非常小,但值得注意的是,对于阅读下划线(_)的ESL员工而言可能不那么混淆(至少比驼峰式(CamelCase)更容易理解);同时,这似乎使一些开发人员感到烦恼,因为他们必须使用不太方便的按键来输入下划线。

关于制定政策,这只是意味着定义在哪些情况下需要使用给定的标记或MDC维度。保持紧密性(集中、刻意),但允许开发人员提供反馈,如果他们觉得维度和标记集对手头的任务不够充分,则进行修改/添加维度和/或属性。

要理解这个策略几乎必须是项目特定的,因为并非每个项目都需要相同类型的日志分析。想象一些噩梦般的情景,然后想象一下你如何希望能够在这种情况下分析日志。您可能不希望编写复杂的脚本来尝试跟踪哪条消息属于哪个上下文,哪个状态在哪个时间,对吗?将任何此类信息编码为维度和标记,并在出现问题时节省一些麻烦。


8
好的回答。我认为基于线程的数据结构MDC也可以用于过滤。 - Ceki
2
很好的回答。但是什么是_ESL员工_? - DerMike
谢谢。英语是我的第二语言。 - user359996

90

首先,MDC。

MDC在一个有一个“实体”与某些行为相关联的环境中非常有用。一个典型的例子是:用户与Web应用程序交互。所以,假设你有许多用户在玩弄你的Web应用程序。使用MDC,你可以轻松地跟踪它们而不会太麻烦。下面是一个简化的例子:

...[Sandy][abcd] clicked on "change profile"
...[Joe][1234] clicked on "weather reports"
...[Joe][1234] clicked on "Europe"
...[Sandy][abcd] clicked on "logout"
...[Joe][1234] clicked on "logout"
...[Sandy][efgh] logged in

在这里,你使用MDC来记录用户名和会话ID。这样,您可以轻松地搜索一个用户的会话,以查看他们所做的一切。

其次,标记。

标记通常用于“特殊”情况,例如针对一些严重错误向管理员发送电子邮件。并非所有错误都属于同一类别;某些错误必须以适当的方式处理。

或者,当用户退出您的服务时,它通常进入INFO日志,但您也可以使用标记来处理此类情况,如果您希望像这样的事件进入单独的日志文件,以便更轻松地监视统计用户退出等事件。

经验法则:

  • MDC用于将多个事件与少量“实体”相关联
  • 标记用于您想要从普通事件中过滤出“特殊”事件的情况

3
这是一个不错的答案,但它只涵盖了使用标记的一个可能用例。在我看来,日志框架功能(如MDC和Markers)存在的目的是为后续对日志进行切片和分析提供更多元数据(例如管理员电子邮件或您提到的单独日志记录情况)。我想知道的是如何创建标记(是否应该有“标准池”标记,是否有一些命名约定需要注意等等)。 - Roland Tepp
4
@Roland:我已经加了一些例子,但是由于定义上它们是无限的,所以我不能添加所有的例子。如果你理解标记的动机和原因,那么使用它们只受你的想象力和常识的限制。 - darioo

36

标记可以用于对单个日志语句进行着色或标记。如何使用这些颜色,即标记,完全取决于您。然而,两种模式似乎很常见(第一种比第二种更常见)。

  1. 触发:某些 appender 可以被指示在出现特定标记时采取操作。例如,SMTPAppender 可以配置为在任何标有 NOTIFY_ADMIN 标记的日志事件上发送电子邮件,而不管日志级别如何。请参阅 logback 文档中关于基于标记的触发。您还可以结合日志级别和标记进行触发。

  2. 过滤:例如,您可以使用 "DB" 颜色/标记来标记所有与持久化相关的日志(在各种多个类文件中)。然后,您可以过滤出 "DB": 禁用除标有 "DB" 标记的日志声明之外的所有日志声明。有关更多信息,请参阅 logback 文档中的过滤器章节(搜索 MarkerFilter)。


14

MDC也可以用于在日志消息中添加与日志变量相关联的方式吗? - Rule

1
MDC的优点在于它们在线程中是有信息的:让我们以一个在结尾发送日志的方法为例。在整个方法和子方法的调用过程中,您可以使用收集到的信息填写MDC。当在结尾处启动日志时,它包含MDC和所有我们可能放置在那里的信息。通过适当的模式,我们可以从MDC中检索信息。
另一方面,标记直接与日志相关联。

我想补充一下,适当的模式通常是"%X",后面没有大括号,这样您就可以获得整个MDC,而不需要每次某些代码(可能在库中)添加或删除MDC时更新模式布局。 - LarryW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接