java 动态创建 Logback Loggers 和 Appenders

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16845067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:08:32  来源:igfitidea点击:

Dynamically Create Logback Loggers and Appenders

javalogginglogback

提问by Michael

I need to dynamically create Logback loggers and sundry bits for classes that load and reload dynamically. I have a variable number of these classes though it will be less than 150 all told. Performance is a big concern and this is a highly-threaded and extremely concurrent environment so the idea of using MDC isn't going to fly due to potentially thousands of calls a second when things go wrong. I also don't want to directly pass the loggers into the classes, I'd like them to just pull them out of the air using getLogger as is typical.

我需要为动态加载和重新加载的类动态创建 Logback 记录器和杂项。我有这些类的可变数量,尽管总而言之将少于 150。性能是一个大问题,这是一个高度线程化和高度并发的环境,因此使用 MDC 的想法不会因为出现问题时每秒可能有数千次调用而飞速发展。我也不想直接将记录器传递到类中,我希望他们像典型的那样使用 getLogger 将它们从空中拉出。

Each class has to log all of it's error messages to it's own error file and all of it's trace messages to it's own trace file. Both of the files need to roll over nightly. Additionally, anything logged in the system has to end up in the main system logs too.

每个类都必须将所有错误消息记录到自己的错误文件中,并将所有跟踪消息记录到自己的跟踪文件中。这两个文件都需要每晚滚动一次。此外,系统中记录的任何内容也必须最终出现在主系统日志中。

I've created the following code snippet to try this idea out. It SEEMS like it would work but the results are not what I'd expect. Here is the test program that can be run directly:

我创建了以下代码片段来尝试这个想法。它似乎可以工作,但结果并不是我所期望的。下面是可以直接运行的测试程序:

package logbacktesting;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.filter.LevelFilter;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.spi.FilterReply;
import ch.qos.logback.core.util.StatusPrinter;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {

        Logger templateLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.myapp");
        LoggerContext loggerContext = templateLogger.getLoggerContext();

        String[] nameList = new String[] {"test1.class", "test2.class"};

        // Set up the pattern
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(loggerContext);
        encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        encoder.start();

        // Spin over the names to create all the needed objects
        for(int i = 0; i < nameList.length; i++) {

            String name = nameList[i];

            // Set up the roll over policies and the name when it rolls over
            TimeBasedRollingPolicy tracePolicy = new TimeBasedRollingPolicy();
            tracePolicy.setContext( loggerContext );
            tracePolicy.setFileNamePattern( name + "-Trace-%d{yyyy-MM-dd}.log" );
            tracePolicy.setMaxHistory( 30 );

            TimeBasedRollingPolicy errorPolicy = new TimeBasedRollingPolicy();
            errorPolicy.setContext( loggerContext );
            errorPolicy.setFileNamePattern( name + "-Error-logFile.%d{yyyy-MM-dd}.log" );
            errorPolicy.setMaxHistory( 30 );

            // Set up the filters to ensure things get split as expected
            LevelFilter traceFilter = new LevelFilter();
            traceFilter.setContext( loggerContext );
            traceFilter.setLevel( Level.TRACE );
            traceFilter.setOnMatch( FilterReply.ACCEPT );
            traceFilter.setOnMismatch( FilterReply.DENY );

            LevelFilter errorFilter = new LevelFilter();
            errorFilter.setContext( loggerContext );
            errorFilter.setLevel( Level.ERROR );
            errorFilter.setOnMatch( FilterReply.ACCEPT );
            errorFilter.setOnMismatch( FilterReply.DENY );

            // Set up the trace and error appenders
            RollingFileAppender rollingFileAppenderTrace = new RollingFileAppender();
            rollingFileAppenderTrace.setContext(loggerContext);
            rollingFileAppenderTrace.setName(name + "-Trace");
            rollingFileAppenderTrace.setFile(name + "-Trace.log");
            rollingFileAppenderTrace.setEncoder(encoder);
            rollingFileAppenderTrace.setRollingPolicy( tracePolicy );
            rollingFileAppenderTrace.addFilter( traceFilter );
            tracePolicy.setParent( rollingFileAppenderTrace );

            RollingFileAppender rollingFileAppenderError = new RollingFileAppender();
            rollingFileAppenderError.setContext(loggerContext);
            rollingFileAppenderError.setName(name + "-Error");
            rollingFileAppenderError.setFile(name + "-Error.log");
            rollingFileAppenderError.setEncoder(encoder);
            rollingFileAppenderError.setRollingPolicy( errorPolicy );
            rollingFileAppenderError.addFilter( errorFilter );
            errorPolicy.setParent( rollingFileAppenderError );

            // Start everything
            tracePolicy.start();
            errorPolicy.start();
            traceFilter.start();
            errorFilter.start();
            rollingFileAppenderTrace.start();
            rollingFileAppenderError.start();

            // attach the rolling file appenders to the logger
            Logger logger = (ch.qos.logback.classic.Logger) loggerContext.getLogger(name);
            logger.addAppender(rollingFileAppenderTrace);
            logger.addAppender(rollingFileAppenderError);

        }

        StatusPrinter.print(loggerContext);

        // Test it to see what happens
        for(int i = 0; i < nameList.length; i++) {

            String name = nameList[i];

            Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(name);
            logger.error("error message" );
            logger.warn("warn message" );
            logger.info("info message" );
            logger.debug("debug message" );
            logger.trace("trace message" );
        }

        Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.myapp");
        logger.error( "generic error message ");


    }

}

Here is the logback.xml file:

这是 logback.xml 文件:

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>

</configuration>

If you run this code, it will properly log everything into the main log file. And it will create 2 trace and 2 error logs as expected. But none of the trace messages will end up in the trace log files and both of the error messages will end up in the class2 error file. It's acting like all 4 appenders are being added to the same logger and only the last appender being added actually works. I'd love to understand what I'm doing where here. Thanks!

如果您运行此代码,它将正确地将所有内容记录到主日志文件中。它将按预期创建 2 个跟踪和 2 个错误日志。但是没有任何跟踪消息会出现在跟踪日志文件中,并且两条错误消息都将出现在 class2 错误文件中。它的行为就像所有 4 个 appender 都被添加到同一个记录器中,只有最后一个 appender 被添加实际工作。我很想了解我在这里做什么。谢谢!

采纳答案by Michael

There were several problems with the code above. First is what Ceki called out: you can't share encoders. Creating two encoders in the loop changed the behavior in the right direction. Second problem was in the XML file, root level should have been trace, not debug. It was obvious after the encoder change.

上面的代码有几个问题。首先是 Ceki 所说的:你不能共享编码器。在循环中创建两个编码器改变了正确方向的行为。第二个问题是在 XML 文件中,根级别应该是跟踪,而不是调试。编码器改变后很明显。

回答by otm

everything into the main log file

一切都进入主日志文件

This is because all loggers will "inherit" the appenders from ROOT logger, you can use logger.setAdditive(false)to disable this behaviour.

这是因为所有记录器都将从 ROOT 记录器“继承”附加程序,您可以使用logger.setAdditive(false)禁用此行为。

But i don't know why you don't have any trace log...

但我不知道为什么你没有任何跟踪日志......

perhaps these two links will give you some inspiration

也许这两个链接会给你一些启发

Logback - set log file name programmatically

Logback - 以编程方式设置日志文件名

how-to-create-logback-loggers-dynamically-pragmatically

How-to-create-logback-loggers-dynamically-pragmatically