我们正在尝试一些新的东西,并在此处发布问题以查看是否可能。
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;
}
}
我已经设计了自定义配置工厂,并将其视为实现此目标的一种方法。
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] 删除。
我来说两句