【问题标题】:Cannot send JUL -> Logback无法发送 JUL -> Logback
【发布时间】:2017-12-15 19:32:27
【问题描述】:

我正在尝试将日志记录从第 3 方应用程序(使用 JUL ConsoleHandler)发送到 logback。我已关注该网站上的所有其他帖子,但无法使其正常工作。我做错了吗?

  • 我在实现捆绑激活器的 RCP 类的开头添加了以下内容

    public class MyTestActivator implements BundleActivator {
        static {
          LogManager.getLogManager().reset();
          SLF4JBridgeHandler.removeHandlersForRootLogger();
          SLF4JBridgeHandler.install();
          java.util.logging.Logger.getGlobal().setLevel(Level.FINEST);
    
        } 
        @Override
        public void start(final BundleContext bundleContext) throws 
          Exception {
            try {
                LoggerContext context = (LoggerContext) LoggerFactory.
                  getILoggerFactory();
    
                JoranConfigurator configurator = new JoranConfigurator();
                  configurator.setContext(context);
                try {
                    context.reset();
                    configurator.doConfigure(getClass().
                    getResourceAsStream("/logback.xml"));
                } catch (JoranException e) {
                    throw new IOException(e.getMessage(), e);
                }
                StatusPrinter.printInCaseOfErrorsOrWarnings(context);
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 我的 feature.xml 文件包含:

    <plugin
          id="jul.to.slf4j"
          download-size="0"
          install-size="0"
          version="0.0.0"
          unpack="false"/>
    
    <plugin
          id="ch.qos.logback.classic"
          download-size="0"
          install-size="0"
          version="0.0.0"
          unpack="false"/>
    
    <plugin
          id="ch.qos.logback.core"
          download-size="0"
          install-size="0"
          version="0.0.0"
          unpack="false"/>
    
  • 我的 logback.xml 包含:

    <configuration>
        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
            <resetJUL>true</resetJUL>
        </contextListener>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>
                    %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
                </pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    

更新:我也尝试了以下方法,但没有按预期工作

    private static final java.util.logging.Logger[] pin;
    static {
        LogManager.getLogManager().reset();
        SLF4JBridgeHandler.removeHandlersForRootLogger();
        SLF4JBridgeHandler.install();
        pin = new java.util.logging.Logger[] { 
            java.util.logging.Logger.getLogger(""),        
            java.util.logging.Logger.getLogger("3rd.party.package") };

        for (java.util.logging.Logger l : pin) {
            l.setLevel(Level.FINEST);
            for (Handler h : l.getHandlers()){
                if (h instanceof ConsoleHandler){
                    h.setFormatter(new Formatter(){
                        public final String format(LogRecord record) { 
                            if (record == null) {
                                return "";
                            } else {
                                return "CONSOLE_MSG:"+record.getMessage();
                            }
                        }
                    });
                }
            }
        }

    }
  • 更新我相信我可以通过添加以下代码代替上一节中的 for 循环来实现它:

    java.util.logging.Logger root = java.util.logging.Logger.getLogger("");
    java.util.logging.Logger myLog = java.util.logging.Logger.getLogger("3rd.party.package");
    myLog.setParent(root);
    myLog.setUseParentHandlers(true);
    java.util.logging.LogManager.getLogManager().getLogger( "" ).setLevel( Level.ALL );
    

唯一的缺点是我可能必须捕获每个记录器并执行此操作。当我查看调试器时,我注意到它们都没有父级(它是空的)

【问题讨论】:

  • 您使用的确切 Java 版本是什么?
  • JDK 1.8.0_71、SLF4J 1.7.25、Logback 1.2.3。请参阅我对您的其他帖子的回复,了解他们如何构建 Logger 对象。

标签: java logging logback rcp


【解决方案1】:

Logger.getGlobal() 不是所有 JUL 记录器的根。所有 JUL 记录器的根是 Logger.getLogger("")。如果您对记录器进行编程更改,那么您必须 pin those loggers 以便在垃圾收集时不会恢复设置。

您需要确保日志记录并被发布到parent handlers 并一直到根记录器。

private static final java.util.logging.Logger[] pin;
static {
    //Pin first.
    pin = new java.util.logging.Logger[] { 
        java.util.logging.Logger.getLogger(""),
        java.util.logging.Logger.getLogger("3rd.party.package") };

    //Setup SLF4J
    LogManager.getLogManager().reset();
    SLF4JBridgeHandler.removeHandlersForRootLogger();
    //SLF4JBridgeHandler.install();
    java.util.logging.Logger.getLogger("").addHandler(new SLF4JBridgeHandler());

    //Change JUL levels.
    for (java.util.logging.Logger l : pin) {
        l.setLevel(Level.FINEST);
    }
}

你也应该试试:

public class MyTestActivator implements BundleActivator {        
    static {
        //Pin first.
        pin = new java.util.logging.Logger[] { 
        java.util.logging.Logger.getLogger(""),
        java.util.logging.Logger.getLogger("3rd.party.package") };

        //Change JUL levels.
        for (java.util.logging.Logger l : pin) {
           l.setLevel(Level.FINEST);
        }
    }

    @Override
    public void start(final BundleContext bundleContext) throws Exception {
        try {
            LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(context);
            try {
                context.reset();
                configurator.doConfigure(getClass().getResourceAsStream("/logback.xml"));
                //Setup SLF4J
                SLF4JBridgeHandler.removeHandlersForRootLogger();
                SLF4JBridgeHandler.install();
            } catch (JoranException e) {
                throw new IOException(e.getMessage(), e);
            }
            StatusPrinter.printInCaseOfErrorsOrWarnings(context);
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }
}

将根 logger 中的 logback 级别设置为 debugtrace。与设置 logback 控制台 appender 的级别相同。

唯一的缺点是我可能必须捕获每个记录器并执行此操作。

Iteration over the installed the loggers 可以执行,但记录器树会随着时间而改变。

唯一的缺点是我可能必须捕获每个记录器并执行此操作。当我查看调试器时,我注意到它们都没有父级(它是空的)

这很奇怪。仅当记录器是根记录器时,父级才应为空。也许您正在使用的 LogManager 中存在错误?

或者,您可以将new SLF4JBridgeHandler() 添加到要监视的每个记录器,但这不如监视根记录器好。

【讨论】:

  • 您好,感谢您的提示。不幸的是,它对我不起作用。我更新了主要帖子以反映我的尝试。我应该这样做吗?
  • @ekjcfn3902039 您的代码仍未固定根记录器。根记录器必须存储在 pin 数组中。
  • 我继续更新了上面显示的代码。将根记录器添加到 pin 对我来说并没有什么不同
  • @ekjcfn3902039 您是否尝试在 logback.xml 中设置 &lt;resetJUL&gt;false&lt;/resetJUL&gt;
  • 是的,反编译 3rd 方包显示他们正在创建一个具有单个名称(MyClass 而不是 my.pkg.MyClass)的记录器并设置 useParentHandlers(false),这可能是原因。跨度>
猜你喜欢
  • 2011-08-26
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 2017-05-26
相关资源
最近更新 更多