log4j2 +以编程方式覆盖Web应用程序中的父自定义ConfigurationFactory

乌雷什·库鲁里(Uresh Kuruhuri)

我们正在尝试一些新的东西,并在此处发布问题以查看是否可能。

TL; DR覆盖Web应用程序中的父自定义ConfigurationFactory。

场景:我们有一堆Web应用程序。这些Web应用程序中的某些将日志写入相同的日志文件,而其他Web应用程序则写入与应用程序相关的单个日志文件。因此,我编写了一个CustomLoggerConfigFactory(为便于讨论,我们将其称为父配置),并将其捆绑在custom-logger-util.jar中,并使用此jar作为Web应用程序中的依赖项,并且记录器在初始化期间网络应用启动。此配置在初始化后将RollingFileAppender写入日志到名为common-logs.log的文件中,该文件运行良好。以下是CustomLoggerConfigFactory的代码。

问题:现在我的问题是,在Web应用程序B中,也将common-logger-util.jar用作依赖项-我如何扩展CustomLoggerConfigFactory以覆盖RollingFileAppender将日志写入appB.log文件中程序化的common-logs.log,不使用配置文件并保持其余配置不变,即使用父配置工厂定义的控制台附加程序,Loggers(包括RootLogger)?谁能解释一下如何实现这一目标?

提前致谢。

package org.custom.logger;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;

import java.net.URI;

@Plugin(name = "CustomLogConfig", category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomLoggerConfigFactory extends ConfigurationFactory {

    static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
        //Set the Logger configuration
        builder.setConfigurationName(name);
        builder.setStatusLevel(Level.TRACE);

        System.out.println("Testing Logger programmatic configuration");
        String region = System.getProperty(CustomLoggerConstants.LOG4J2_ENV);
        System.out.println("ENV|" + region);

        //Create a pattern layout (common for console and rolling file appenders)
        LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", CustomLoggerConstants.KP_STD_CONVERSIONPATTERN);

        FilterComponentBuilder thresholdFilter = builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
                .addAttribute("level", getLogLevel(region));

        //Create a Console appender
        AppenderComponentBuilder appenderBuilder = builder.newAppender(CustomLoggerConstants.LOG_TO_CONSOLE, "CONSOLE")
                                                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
        appenderBuilder.add(layoutBuilder).addAttribute("pattern", CustomLoggerConstants.KP_STD_CONVERSIONPATTERN);
        appenderBuilder.add(thresholdFilter);
        builder.add(appenderBuilder);

        //Create a policy for adding it to rolling file appender
        ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
                .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "5M"));

        //Create a rolling file appender
        AppenderComponentBuilder rollingFileAppender = builder.newAppender(CustomLoggerConstants.LOG_TO_ROLLING_FILE, "RollingFile")
                .addAttribute("fileName", CustomLoggerConstants.FILENAME + CustomLoggerConstants.FILE_EXTN)
                .addAttribute("filePattern", CustomLoggerConstants.FILENAME + "-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz")
                .add(layoutBuilder)
                .addComponent(triggeringPolicy);
        builder.add(rollingFileAppender);

        //Create a logger
        builder.add(builder.newLogger("org.kp", getLogLevel(region))
                .add(builder.newAppenderRef(CustomLoggerConstants.LOG_TO_ROLLING_FILE))
                .add(builder.newAppenderRef(CustomLoggerConstants.LOG_TO_CONSOLE))
                .addAttribute("additivity", false)
        );

        //Create root logger
        builder.add(builder.newRootLogger(Level.INFO)
                .add(builder.newAppenderRef(CustomLoggerConstants.LOG_TO_CONSOLE))
        );

        System.out.println("Logger programmatic configuration is almost done and ready to be initialized.");
        return builder.build();
        //LoggerContext context = Configurator.initialize(builder.build());
    }

    @Override
    protected String[] getSupportedTypes() {
        return new String[]{"*"};
    }

    @Override
    public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
        return getConfiguration(loggerContext, configurationSource.toString(), null);
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, String name, URI configLocation) {
        ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
        return createConfiguration(name, builder);
    }

    private static Level getLogLevel(String region) {
        switch (region) {
            case CustomLoggerConstants.DEV:
                return Level.DEBUG;
            case CustomLoggerConstants.QA:
            case CustomLoggerConstants.LOAD:
            case CustomLoggerConstants.PREV:
                return Level.INFO;
            
        }
        return null;
    }
}
乌雷什·库鲁里(Uresh Kuruhuri)

我已经设计了自定义配置工厂,并将其视为实现此目标的一种方法。

下面是解决方案。 在此处输入图片说明

The solution is built on Java 8. The interfaces in Java 8 now allow you to define default implementation for the methods and used them. The log4j2 provided ConfigurationFactory is already an abstract class but I wanted to separate the creation of configuration and to the individual components having the default implementation.

The LoggerConfigFactory in the below image is the custom default implementation that can be used in any of the other apps just by including it (however, in my case, I packaged CustomConfigBuilder, LoggerConfigFactory and LoggerConstants in a jar file).

In the event in the application if any or all of the individual components needs to be defined, all it is required is to create config factory class (AppSpecificLoggerConfigFactory) that extends the default LoggerConfigFactory.

这工作了!以下是用于参考的代码。

package org.custom.logger;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;


public interface CustomConfigBuilder {

    default Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder, String filename) {
        //Set the Logger configuration
        setLogConfig(name, builder);

        System.out.println("Testing Logger programmatic configuration for " + name);
        String region = System.getProperty(LoggerConstants.LOG4J2_ENV, "PROD");
        System.out.println("ENV from properties file|" + region);
        /*String region = System.getProperty(LoggerConstants.LOG4J2_ENV);
        if(null == region || region.equals("")){
            region = LoggerConstants.PROD;
        }
        System.out.println("ENV from sys props|" + region);*/
        //Create a pattern layout (common for console and rolling file appenders)
        LayoutComponentBuilder layoutBuilder = createLayoutBuilder(builder);
        FilterComponentBuilder thresholdFilter = createThresholdFilter(builder, region);

        //Create a Console appender
        AppenderComponentBuilder appenderBuilder = builder.newAppender(LoggerConstants.LOG_TO_CONSOLE, "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
        appenderBuilder.add(layoutBuilder).addAttribute("pattern", LoggerConstants.CONVERSIONPATTERN);
        appenderBuilder.add(thresholdFilter);
        builder.add(appenderBuilder);

        //Create a policy for adding it to rolling file appender
        ComponentBuilder triggeringPolicy = createTriggeringPolicy(builder);

        //Create a rolling file appender
        AppenderComponentBuilder rollingFileAppender = createRollingFileAppender(builder, layoutBuilder, triggeringPolicy, filename);
        builder.add(rollingFileAppender);

        LoggerComponentBuilder appLogger = createAppLogger(builder, region);
        //Create a logger
        builder.add(appLogger);

        //Create root logger
        RootLoggerComponentBuilder rootLogger = createRootLogger(builder);
        builder.add(rootLogger);

        System.out.println("Logger programmatic configuration for " + name + " is almost done and ready to be initialized.");
        return builder.build();
        //LoggerContext context = Configurator.initialize(builder.build());
    }

    default void setLogConfig(String name, ConfigurationBuilder<BuiltConfiguration> builder) {
        builder.setConfigurationName(name);
        builder.setStatusLevel(Level.TRACE);
    }

    default LayoutComponentBuilder createLayoutBuilder(ConfigurationBuilder<BuiltConfiguration> builder) {
        LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", LoggerConstants.CONVERSIONPATTERN);
        return layoutBuilder;
    }

    default FilterComponentBuilder createThresholdFilter(ConfigurationBuilder<BuiltConfiguration> builder, String region) {
        FilterComponentBuilder thresholdFilter = builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
                .addAttribute("level", getLogLevel(region));
        return thresholdFilter;
    }
    default ComponentBuilder createTriggeringPolicy(ConfigurationBuilder<BuiltConfiguration> builder) {
        ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
                .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "5M"));
        return triggeringPolicy;
    }
    default AppenderComponentBuilder createRollingFileAppender(ConfigurationBuilder<BuiltConfiguration> builder, LayoutComponentBuilder layoutBuilder, ComponentBuilder triggeringPolicy, String filename) {
        System.out.println("Filename|" + filename);
        AppenderComponentBuilder rollingFileAppender = builder.newAppender(LoggerConstants.LOG_TO_ROLLING_FILE, "RollingFile")
                .addAttribute("fileName", filename + LoggerConstants.FILE_EXTN)
                .addAttribute("filePattern", filename + "-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz")
                .add(layoutBuilder)
                .addComponent(triggeringPolicy);
        return rollingFileAppender;
    }

    default LoggerComponentBuilder createAppLogger(ConfigurationBuilder<BuiltConfiguration> builder, String region) {
        return builder.newLogger("org.app", getLogLevel(region))
                .add(builder.newAppenderRef(LoggerConstants.LOG_TO_ROLLING_FILE))
                .add(builder.newAppenderRef(LoggerConstants.LOG_TO_CONSOLE))
                .addAttribute("additivity", false);
    }

    default RootLoggerComponentBuilder createRootLogger(ConfigurationBuilder<BuiltConfiguration> builder) {
        return builder.newRootLogger(Level.INFO)
                .add(builder.newAppenderRef(LoggerConstants.LOG_TO_CONSOLE));
    }

    default Level getLogLevel(String region) {
        switch (region) {
            case LoggerConstants.DEV:
                return Level.DEBUG;
            case LoggerConstants.QA:
            case LoggerConstants.LOAD:
            case LoggerConstants.PREV:
                return Level.INFO;
            case LoggerConstants.PROD:
                return Level.ERROR;
        }
        return null;
    }
}

package org.custom.logger;

public class LoggerConstants {
    public static final String CONVERSIONPATTERN = "%d{ISO8601} [%t] %-5p %c{3} - %m%n";
    public static final String FILENAME = "/logs/logfile";
    public static final String FILE_EXTN = ".log";
    public static final String LOG_TO_ROLLING_FILE = "LogToRollingFile";
    public static final String LOG_TO_CONSOLE = "LogToConsole";
    //public static final String LOG4J2_ENV = "LOG4J2_ENV";
    public static final String LOG4J2_ENV = "log4j2.env";

    public static final String DEV = "DEV";
    public static final String QA = "QA";
    public static final String LOAD = "LOAD";
    public static final String PREV = "PREV";
    public static final String PROD = "PROD";

}

package org.custom.logger;

import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;

import java.net.URI;

@Plugin(name = "CustomLogConfig", category = ConfigurationFactory.CATEGORY)
@Order(50)
public class LoggerConfigFactory extends ConfigurationFactory implements CustomConfigBuilder {

    public Configuration createConfiguration(String name, ConfigurationBuilder<BuiltConfiguration> builder) {
        System.out.println("Invoking  default config factory");
        createConfiguration(name, builder, LoggerConstants.FILENAME);
        return null;
    }

    @Override
    protected String[] getSupportedTypes() {
        return new String[]{"*"};
    }

    @Override
    public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
        return getConfiguration(loggerContext, configurationSource.toString(), null);
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, String name, URI configLocation) {
        ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
        return createConfiguration(name, builder);
    }

}

以上三个都打包到一个jar文件中。如果应用程序要使用LoggerConfigFactory中定义的默认配置,则需要全部内容以将该jar文件包含在应用程序类路径中,或者如果它是Web应用程序,则应包含在其WEB-INF / lib中。

例如,如果应用程序希望拥有自己的日志文件而文件名不同,则需要对其进行扩展。请参见下面的代码。注意,请确保@Order批注的值大于默认配置工厂中定义的值。

import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.custom.logger.LoggerConfigFactory;

@Plugin(name = "AppCustomLogConfig", category = ConfigurationFactory.CATEGORY)
@Order(55)
public class AppSpecificLoggerConfigFactory extends LoggerConfigFactory {

    String filename = "/logs/appSpecificLogFilename";
    @Override
    public Configuration createConfiguration(String name, ConfigurationBuilder<BuiltConfiguration> builder) {
        System.out.println("Invoking App Specific config factory");
        return createConfiguration(name, builder, filename);
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用ConfigurationFactory以编程方式配置log4j2

来自分类Dev

log4j2中基于时间的触发策略

来自分类Dev

如何为log4j2定义全局PatternLayout?

来自分类Dev

Web应用程序中的Log4j2配置

来自分类Dev

Web应用程序中的Log4j2:MongoCleaner线程创建内存泄漏

来自分类Dev

如何自定义log4j2 RollingFileAppender?

来自分类Dev

Log4j2自定义翻转策略

来自分类Dev

在log4j2中创建惰性消息

来自分类Dev

log4j2 Web查找不起作用

来自分类Dev

Log4J2中的可加性(2.5)

来自分类Dev

Log4j2自定义包装器

来自分类Dev

使用log4j-web.jar在Web应用程序中配置Log4j2

来自分类Dev

自定义log4j2附加程序在Java 11中不起作用

来自分类Dev

覆盖log4j2的日期类

来自分类Dev

Web应用程序中的Log4j2:MongoCleaner线程创建内存泄漏

来自分类Dev

如何在log4j2中更改htmllayout

来自分类Dev

如何在log4j2中配置StatisticsCsvLayout

来自分类Dev

如何在Web应用程序中查找log4j2的属性参数?

来自分类Dev

从log4j到log4j2自定义RollingPolicy

来自分类Dev

在log4j2中等效于DenyAllFilter

来自分类Dev

带有Servlet 3.0的Spring Web应用程序中的Log4j2

来自分类Dev

在log4j2中提供动态日期

来自分类Dev

Log4j2自定义包装器

来自分类Dev

使用log4j-web.jar在Web应用程序中配置Log4j2

来自分类Dev

在Mule中动态选择log4j2配置

来自分类Dev

在 NetBeans 中设置 Log4j2,基本配置

来自分类Dev

未在 OSGi 环境中应用的 Log4j2 自定义插件

来自分类Dev

在 log4j2 中配置 FixedWindowRollingPolicy

来自分类Dev

Log4j2 - Stackoverflow at AwaitCompletionReliabilityStrategy 使用编程配置