如何以编程方式正确配置log4j2?

时间:2018-12-01 01:48:58

标签: java log4j log4j2 slf4j

我正在尝试将log4j2设置为使用RollingFileAppender写入日志。我想以编程方式配置日志记录系统,而不是使用XML文件。

这是我尝试的内容(与https://logging.apache.org/log4j/2.x/manual/customconfig.html#Configurator上的文档基本相同):

public static void configure(String rootLevel, String packageLevel) {
    ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory
        .newConfigurationBuilder();

    builder.setConfigurationName("RollingBuilder");
    builder.setStatusLevel(Level.TRACE);

    // Create a rolling file appender

    LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
        .addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %c{1}:%L - %m%n");

    ComponentBuilder triggeringPolicy =
        builder
            .newComponent("Policies")
            .addComponent(
                builder
                    .newComponent("SizeBasedTriggeringPolicy")
                    .addAttribute("size", "200M")
            );

    AppenderComponentBuilder appenderBuilder =
        builder
            .newAppender("rolling", "RollingFile")
            .addAttribute("fileName", "log")
            .addAttribute("filePattern", "log.%d.gz")
            .add(layoutBuilder)
            .addComponent(triggeringPolicy);

    builder.add(appenderBuilder);

    // Create new logger

    LoggerComponentBuilder myPackageLoggerBuilder =
        builder.newLogger("com.mypackage", packageLevel)
            .add(builder.newAppenderRef("rolling"))
            .addAttribute("additivity", false);
    builder.add(myPackageLoggerBuilder);

    RootLoggerComponentBuilder rootLoggerBuilder =
        builder
            .newRootLogger(rootLevel)
            .add(builder.newAppenderRef("rolling"));
    builder.add(rootLoggerBuilder);

    // Initialize logging
    Configurator.initialize(builder.build());
}

我在main方法的开头调用configure()方法。运行程序时,会创建一个名为log的文件,但是所有日志输出都变为标准输出,并且log文件仍然为空。

有人可以帮我弄清楚我的配置有什么问题吗?

如果不起作用,我没有使用任何log4j配置文件。在我的代码中也使用slf4j API。依赖关系-

org.apache.logging.log4j:log4j-api:2.11.1
org.apache.logging.log4j:log4j-core:2.11.1
org.apache.logging.log4j:log4j-slf4j-impl:2.11.1
org.slf4j:slf4j-api:1.7.25

1 个答案:

答案 0 :(得分:0)

首先,此答案是对您评论中提供的其他信息的回应。

  

我的要求是我想控制不同日志级别   启动程序时通过命令行标志打包程序

由于您要使用程序参数来控制日志级别,因此建议您看看Main Arguments LookupRouting Appender。结合使用这两个功能,您可以设置日志记录配置,以根据程序参数将日志事件发送到适当的附加程序。

我将提供一个简单的示例来帮助您。

首先,这里是一个示例Java类,该类生成一些日志事件:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.lookup.MainMapLookup;

public class SomeClass {

    private static Logger log = LogManager.getLogger();

    public static void main(String[] args){
        MainMapLookup.setMainArguments(args);

        if(log.isDebugEnabled())
            log.debug("This is some debug!");
        log.info("Here's some info!");
        log.error("Some error happened!");
    }
}

接下来是log4j2的配置文件(有关详细信息,请参见代码中的注释):

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Routing name="myRoutingAppender">
            <!-- log events are routed to appenders based on the logLevel program argument -->
            <Routes pattern="$${main:logLevel}">
                <!-- If the logLevel argument is followed by DEBUG this route is used -->
                <Route ref="DebugFile" key="DEBUG" />
                <!-- If the logLevel argument is omitted or followed by any other value this route is used -->
                <Route ref="InfoFile" />
            </Routes>
        </Routing>

        <!-- This appender is not necessary, was used to test the config -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <!-- Below are the 2 appenders used by the Routing Appender from earlier -->
        <File name="DebugFile" fileName="logs/Debug.log" immediateFlush="true"
            append="false">
            <PatternLayout
                pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </File>

        <File name="InfoFile" fileName="logs/Info.log" immediateFlush="true"
            append="false">
            <PatternLayout
                pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <LevelRangeFilter minLevel="FATAL" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
        </File>
    </Appenders>

    <Loggers>
        <!-- Root logger is set to DEBUG intentionally so that debug events are generated.
             However, events may be ignored by the LevelRangeFilter depending on where they
             are routed by the Routing Appender
         -->
        <Root level="DEBUG">
            <AppenderRef ref="Console" />
            <AppenderRef ref="myRoutingAppender" />
        </Root>
    </Loggers>
</Configuration>

如果不提供“ logLevel”参数,则使用此配置,然后默认情况下会将日志事件路由到“ InfoFile”附加程序,并且比{INFO}更具体的事件都将通过LevelRangeFilter忽略。

如果提供了“ logLevel”参数并后跟“ DEBUG”,则日志事件将路由到“ DebugFile”附加程序,并且所有事件都不会被忽略。

请注意,我确实尝试使用查找来设置日志级别,但是似乎无法通过查找来配置日志级别参数。这就是为什么我不得不使用这种替代方法。我对这种方法的担心是,正如我在配置文件中的注释中指出的那样,日志级别必须保持在DEBUG,这意味着即使不使用DEBUG事件,您也始终会生成DEBUG事件。这可能会影响性能。一种解决方法是使用程序参数来确定是否需要生成调试事件。例如:

通常,您将使用:

if(log.isDebugEnabled())
    log.debug("This is some debug!");

,但是在使用上述配置时,您将使用类似以下内容:

if("DEBUG".equals(args[1]))
    log.debug("This is some debug!");

,如果需要,您可以使用枚举(甚至可以使用log4j2提供的Level类)来提高效率。

我希望这可以帮助您入门。