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?