java - Logback 上下文选择器的实际使用

标签 java logging logback slf4j

Logback 上的文档 logging separation表示我可以使用 context selectors在同一个 JVM 上创建不同的日志配置。不知何故,上下文选择器将允许我调用 LoggerFactory.getLogger(Foo.class)并且,根据上下文,我会得到一个不同配置的记录器。

不幸的是,这些示例仅在专门配置的 Web 服务器(例如 Tomcat 或 Jetty)的上下文中处理 JNDI。我想知道如何自己实际使用上下文选择器,例如在非 Web 应用程序中。

我的目标是在同一个 JVM 上拥有多个日志配置。这是一种场景:

  • 我希望一个线程使用默认的 logback.xml 来获取记录器类路径上的配置。
  • 我想要另一个线程使用另一个 logback.xml 来获取记录器从自定义目录。
  • 我想要第三个线程从编程配置中获取记录器。

  • 我提供这些示例场景只是为了了解上下文选择器的实际使用——我将如何在现实生活中使用它们做一些有用的事情。
  • 我如何使用上下文选择器来实现上述场景,以便 LoggerFactory.getLogger(Foo.class)根据线程从正确的配置返回记录器?
  • 如果上下文选择器不能胜任任务,我如何手动获得 ILoggerFactory可以从编程配置中为我提供记录器的实例?
  • 最佳答案

    我问这个问题是为了防止我需要跟踪 Logback 源代码,但由于最初的答案不够充分,我最终不得不这样做。那么让我解释一下 SLF4J+Logback 系统的初始化以及它与上下文选择器的关系。

    SLF4J 是一个日志 API,它允许各种实现,其中之一是 Logback。

  • 当第一个请求被发送到 org.slf4j.LoggerFactory.getLogger(...) ,SLF4J框架通过创建org.slf4j.impl.StaticLoggerBinder来初始化.诀窍是StaticLoggerBinder不随 SLF4J 一起分发;它实际上是在使用的任何日志记录实现中实现的(例如 Logback)。这是加载特定实现的一种有点麻烦的方法(服务加载器可能是更好的选择),但这有点离题了。
  • Logback 对 StaticLoggerBinder 的实现创建一个单例 ch.qos.logback.classic.util.ContextSelectorStaticBinder .这是设置上下文选择器的类。逻辑类似于下面概述的内容。

    一种。如果“logback.ContextSelector”系统属性包含“JNDI”,使用 ContextJNDISelector .

    湾如果"logback.ContextSelector"系统属性包含其他任何内容,假设该值是上下文选择器类的名称并尝试实例化它。

    C。否则如果没有 "logback.ContextSelector"系统属性,使用 DefaultContextSelector .
  • 如定制 ContextSelector使用,ContextSelectorStaticBinder将使用带有 LoggerContext 的构造函数实例化它作为参数,并将其传递给默认 LoggerContext其中StaticLoggerBinder已创建并自动配置。 (更改默认配置策略是一个单独的主题,我不会在这里介绍。)

  • 正如 Pieter 在另一个答案中指出的那样,安装自定义上下文选择器的方法是在 "logback.ContextSelector" 中提供实现类的名称。系统属性。不幸的是,这种方法有点不稳定,显然必须在 1) 手动和 2) 进行任何 SLF4J 调用之前完成。 (这里再次使用服务加载器机制会更好;我已提交问题 LOGBACK-1196 以进行此改进。)

    如果您设法安装了自定义 Logback 上下文选择器,您可能希望存储 LoggerContext您在构造函数中接收,以便您可以在 ContextSelector.getDefaultLoggerContext() 中返回它.除此之外,最重要的方法是ContextSelectorContextSelector.getLoggerContext() ;通过此方法,您将确定适合当前上下文的记录器上下文并返回它。
    LoggerContext这里非常重要的是 ch.qos.logback.classic.LoggerContext ,它实现了 ILoggerFactory .当您访问主 org.slf4j.LoggerFactory.getLogger(...)方法,它使用单例 StaticLoggerBinder (上面讨论过)查找记录器工厂。对于登录 StaticLoggerBinder将使用单例 ContextSelectorStaticBinder (也在上面讨论过)希望能回到你现在安装的自定义 LoggerContext .

    ( ContextSelector.getLoggerContext(String name)ContextSelector.detachLoggerContext(String loggerContextName)ContextSelector.getContextNames() 方法似乎只在诸如 JNDI 上下文选择器之类的情况下使用,在这种情况下,您希望使用名称跟踪上下文选择器。如果您不需要命名上下文选择器,看来您可以安全地返回 null 和适合这些方法的空列表。)

    因此定制ContextSelector只需提供一些 LoggerContext为调用线程适当配置;此 LoggerContext将作为 ILoggerFactory基于 LoggerContext 创建一个记录器配置。配置包含在 Logback documentation 中;也许这里的讨论更清楚地说明了 Logback 记录器上下文的全部内容。

    至于关联 LoggerContext 的实际机制有一个线程,这对我来说从来都不是问题。很简单:我将使用我自己的 Csar库,可以轻松处理此类事情。现在我已经知道如何 Hook 到记录器上下文选择过程,我已经在名为 Clogr 的记录辅助库中实现了这一点。它使用 Csar,我现在已经公开发布了。

    因为我最终不得不自己做所有的研究,所以我会将我自己的答案标记为已接受的答案,除非有人在其他答案之一中指出我没有涵盖的重要内容。

    关于java - Logback 上下文选择器的实际使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38208617/

    相关文章:

    Android - 将 ostream 输出正确映射到 android native 日志?

    android - 使用 res/raw 文件夹中的 mp3 设置铃声

    azure - 是否可以向 azure 数据工厂管道中的数据添加具有特定值的列

    logging - 一个 appender 中的多个过滤器

    java - 使用 Tuckey 的 URL 重写过滤器向 URL 添加尾部斜杠

    java - PBEKeySpec iterationCount 和 keyLength 参数有什么影响?

    java - 使用 Java (Jackson) 读取 JSON 中嵌套键的值

    Spring-Boot 在 Logback 中包含构建信息作为 SpringProperty

    spring - Log4jConfigListener 用于 Spring MVC 应用程序中的 logback

    java - 在工作流重新配置时禁止进入工作线程