日志记录和配置系统:循环依赖

Logging and Configuration Systems: Circular Dependency

假设一个典型场景,应用程序的初始设置在启动时从配置文件加载。该应用程序还有一个记录器。记录器的参数(例如详细级别、日志文件路径等)理想情况下也存储在配置文件中。但是,也希望配置加载器记录有关参数加载的信息,例如

Attempting to load parameter LogVerbosity. Parameter is absent. Using the default value: 4.

因此,我们看到了两个组件之间的循环依赖。配置加载器需要一个随时可用的记录器,而记录器需要配置参数来初始化自己。在我看来,这似乎是一个典型的问题,足以对它有规范的解决方案,但我找不到任何东西。

当然,可以推出一些临时解决方案,但我对最佳行业实践很感兴趣。

希望问题有道理。

我假设您想要记录参数以便以后能够调查它们,例如在出现错误的情况下。很明显,只有将它们保存在文件或其他存储中才有可能。这意味着记录器 必须 正确配置才能这样做。所以基本问题是:

我们可以假设记录器至少能够记录启动参数吗?

这个案例很简单。我只是:

  1. 读取记录器的配置参数。
  2. 初始化记录器。
  3. 记录器的日志参数。
  4. 读取其他参数。
  5. 记录其他参数。

这个案例比较复杂。我认为一个好的解决方案是为记录器使用一组默认的、硬编码的参数。它将保证可以安全地记录启动参数:

  1. 使用默认(硬编码)参数初始化记录器。
  2. 读取配置参数。
  3. 日志参数。
  4. 根据配置文件中的参数初始化记录器。
  5. 再次尝试记录参数。

如果记录器配置正确,您将能够在标准日志位置找到所有参数。如果配置错误,您仍然可以在默认(硬编码)位置找到它们。

或者,您可以使用 fstream...[=11 等标准机制将启动参数简单地写入文件(在应用程序的工作目录中),而不是在步骤 1 中使用记录器=]

补充评论

一些日志库,如 nlog 可以配置(throwExceptions = true)以在配置错误的情况下引发错误。操作系统应该记录未处理的异常。

如果您使用此类日志库,您可以打开此选项并使用上面的解决方案 1。如果应用程序启动,那么您将在日志中找到启动参数。如果没有启动,您应该检查系统日志。

我会说规范的解决方案是:不要混用日志记录和配置!

想象一下,配置文件解析触发了一个错误(但你还不知道!)。您更改配置文件以启用日志记录。现在解析不会触发错误,一切看起来都正常,直到您再次禁用日志记录...

所以:更一般地说,从原则上讲,人们希望最大限度地减少调试基础设施(包括日志记录)对程序造成的干扰;在理想情况下,调试功能将与应用程序所做的任何事情正交,以避免导致heisenbugs。将普通配置与日志配置混合已经违反了这一原则。

而且根据经验,您可以看到著名的日志记录库是如何工作的:它们都有自己的配置文件,独立于应用程序中正在进行的任何配置,因此您可以更改日志记录行为而不会弄乱应用程序本身。因此,您可以重复一个有问题的 运行 应用程序,仅更改其日志记录行为,但愿别无其他。这就是 Log4j 及其端口系列或已经提到的 nlog 的工作方式。