To define more than one filter for an element in log4j (version 2) a composite filter is required (according to the documentation). I can not figure out how to create/add such a filter element when using programmatic configuration:
import java.io.IOException;
import java.net.URI;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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.builder.api.AppenderComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.CompositeFilterComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.KeyValuePairComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
public class ConfigurationFactory_Demo {
public static void main(String[] args) {
ConfigurationFactory configurationFactory = new ConfigurationFactoryClass();
ConfigurationFactory.setConfigurationFactory(configurationFactory);
Logger logger = LogManager.getLogger("com.logger");
logger.info( String.format("Logging Event"));
}
public static class ConfigurationFactoryClass extends ConfigurationFactory {
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
return getConfiguration(loggerContext, source.toString(), null);
}
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
ConfigurationBuilder builder = newConfigurationBuilder();
return createConfiguration(name, builder);
}
@Override
protected String[] getSupportedTypes() {
return new String[] {"*"};
}
Configuration createConfiguration(final String configurationName, ConfigurationBuilder configuration) {
configuration.setConfigurationName(configurationName);
configuration.setStatusLevel(Level.INFO);
// Create appender:
AppenderComponentBuilder appenderComponent = configuration.newAppender("stdout", "CONSOLE");
appenderComponent.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
LayoutComponentBuilder layoutComponent = configuration.newLayout("PatternLayout");
layoutComponent.addAttribute("pattern", "%msg%n");
appenderComponent.add(layoutComponent); // adding layout to appender
configuration.add(appenderComponent); // adding appender to configuration
// Create root logger:
RootLoggerComponentBuilder rootLoggerComponent = configuration.newRootLogger(Level.ERROR);
rootLoggerComponent.add(configuration.newAppenderRef("stdout"));
configuration.add(rootLoggerComponent); // adding logger to configuration
// Create logger:
LoggerComponentBuilder loggerComponent = configuration.newLogger("com.logger", Level.TRACE);
loggerComponent.addAttribute("additivity", false);
AppenderRefComponentBuilder appenderRefComponent = configuration.newAppenderRef("stdout");
appenderRefComponent.addAttribute("level", "TRACE");
// Create filter 'Marker':
FilterComponentBuilder filterComponent_marker = configuration.newFilter("MarkerFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL);
filterComponent_marker.addAttribute("marker", "MarkerTag");
// Create filter 'Thread Context Map:
FilterComponentBuilder filterComponent_threadContextMap;
filterComponent_threadContextMap = configuration.newFilter("ThreadContextMapFilter", Filter.Result.ACCEPT, Filter.Result.DENY);
KeyValuePairComponentBuilder keyValuePairComponent;
keyValuePairComponent = configuration.newKeyValuePair("key", "value");
filterComponent_threadContextMap.addComponent(keyValuePairComponent);
boolean useCompositeFilter = false;
if (useCompositeFilter) {
CompositeFilterComponentBuilder filterComponent_composite = null; // HOW TO INITIALIZE 'CompositeFilterComponentBuilder' ?
filterComponent_composite.add(filterComponent_marker);
filterComponent_composite.add(filterComponent_threadContextMap);
// appenderRefComponent.add(filterComponent_composite); // HOW TO ADD 'CompositeFilterComponentBuilder' to appender-reference ?
} else {
appenderRefComponent.add(filterComponent_marker); // adding filter directly to appender-reference
appenderRefComponent.add(filterComponent_threadContextMap); // adding second filter directly to appender-reference (NOT ALLOWED)
}
loggerComponent.add(appenderRefComponent); // adding appender-reference to logger
configuration.add(loggerComponent); // adding logger to configuration
try { configuration.writeXmlConfiguration(System.out); } catch (IOException e) {}
BuiltConfiguration buildConfiguration = configuration.build();
return buildConfiguration;
}
}
}
This Java code results in the configuration below. It generates the error "AppenderRef has no parameter that matches element ThreadContextMapFilter".
<?xml version="1.0" ?> <Configuration name="18b4aac2" status="INFO"> <Appenders> <CONSOLE name="stdout" target="SYSTEM_OUT"> <PatternLayout pattern="%msg%n"/> </CONSOLE> </Appenders> <Loggers> <Root level="ERROR"> <AppenderRef ref="stdout"/> </Root> <Logger name="com.logger" level="TRACE" additivity="false"> <AppenderRef ref="stdout" level="TRACE"> <MarkerFilter onMatch="ACCEPT" onMismatch="NEUTRAL" marker="MarkerTag"/> <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY"> <KeyValuePair key="key" value="value"/> </ThreadContextMapFilter> </AppenderRef> </Logger> </Loggers> </Configuration>
The correct configuration should be:
<?xml version="1.0" ?> <Configuration name="18b4aac2" status="INFO"> <Appenders> <CONSOLE name="stdout" target="SYSTEM_OUT"> <PatternLayout pattern="%msg%n"/> </CONSOLE> </Appenders> <Loggers> <Root level="ERROR"> <AppenderRef ref="stdout"/> </Root> <Logger name="com.logger" level="TRACE" additivity="false"> <AppenderRef ref="stdout" level="TRACE"> <Filters> <MarkerFilter onMatch="ACCEPT" onMismatch="NEUTRAL" marker="MarkerTag"/> <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY"> <KeyValuePair key="key" value="value"/> </Filters> </ThreadContextMapFilter> </AppenderRef> </Logger> </Loggers> </Configuration>
How is it possible to programmatically define a composite filter in this case?
You can instantiate a CompositeFilter using the ConfigurationBuilder.newComponent() method:
appenderRefComponent.addComponent(
configuration.newComponent("filters")
.addComponent(filterComponent_marker)
.addComponent(filterComponent_threadContextMap)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With