在上下文范围内使用时如何使 log4j2 自定义过滤器对象工作?
How to make log4j2 custom filter objects work when used context-wide?
我正在尝试根据 the documentation 使自定义过滤器在自定义范围内工作。
我开始认为以这种方式使用自定义过滤器存在问题,因为默认过滤器被正确调用而自定义过滤器没有被正确调用。我有的是:
ThresholdFilterCustom.java(与 ThresholdFilter 相同,创建仅用于调试):
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
@Plugin(name = "ThresholdFilterCustom", category = "Core", elementType = "filter", printObject = true)
public final class ThresholdFilterCustom extends AbstractFilter {
private final Level level;
private ThresholdFilterCustom(Level level, Result onMatch, Result onMismatch) {
super(onMatch, onMismatch);
this.level = level;
}
public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
return filter(level);
}
@Override
public Result filter(LogEvent event) {
return filter(event.getLevel());
}
private Result filter(Level level) {
// Look here! It should always match! not even filtering!
return onMatch;
}
@Override
public String toString() {
return level.toString();
}
/**
* Create a ThresholdFilterCustom.
* @param loggerLevel The log Level.
* @param match The action to take on a match.
* @param mismatch The action to take on a mismatch.
* @return The created ThresholdFilterCustom.
*/
@PluginFactory
public static ThresholdFilterCustom createFilter(@PluginAttribute(value = "level", defaultString = "ERROR") Level level,
@PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") Result onMatch,
@PluginAttribute(value = "onMismatch", defaultString = "DENY") Result onMismatch) {
return new ThresholdFilterCustom(level, onMatch, onMismatch);
}
}
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Filters>
<ThresholdFilterCustom level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<!-- <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
</Filters>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
如果我取消评论
<!-- <ThresholdFilterCustom level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
我在控制台中没有看到 logger.debug("logmessage") 记录的消息
但如果我取消注释
<!-- <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
我 看到 logger.debug("logmessage") 记录的消息,尽管它们之间的行为应该是相同的。为什么会这样?这可能是 log4j2 问题吗?
使用调试器后,我看到自定义过滤器中甚至没有调用过滤器函数,但自定义过滤器正在实例化。
如果我将它们放在记录器中,它们会正常工作。但是在上下文范围内放置它们时它们不起作用。
答案是here。
对于登陆这里的人:这里已经修复了。简而言之,似乎方法的 javadoc 混淆了。要实现上下文范围的过滤器,应该覆盖其他方法,即不是 filter(LogEvent event) 的方法。
根据 Ralph Goers 的评论:
The plugin is being properly constructed and is being called. However,
you did not override all the filter methods. Most of them default to
return NEUTRAL, which is what the method did in this case. It probably
would make more sense to have AbstractFilter default to calling one of
the other methods so that no so many methods need to be overridden.
他的另一个答案:
When the global Filters are evaluated a LogEvent has not been
constructed. So if you want to only support the global filter then you
need to implement all the methods that don't take a LogEvent.
Likewise, to use the Filter in other places you need to only implement
the method that accepts a LogEvent. Yes, I think the Javadoc has it
backwards.
What I mean with regard to the default methods is that there are 3
filter methods that explicitly return NEUTRAL.
public Result filter(final Logger logger, final Level level, final
Marker marker, final Message msg,final Throwable t);
public Result filter(final Logger logger, final Level level final Marker
marker, final Object msg,final Throwable t);
public Result filter(final Logger logger, final Level level, final Marker
marker, final String msg, final Object... params);
So all 3 of these need to be implemented In a
Filter such as the one you created. All the other methods that accept
a Logger end up calling the method above that accepts the varargs
Object (i.e. an Object array) as the last parameter. It would make
sense to me that the first 2 methods should also call the third method
as the default instead of returning NEUTRAL. However, that would mean
losing the explicit knowledge that one of the parameters was a
Throwable, which I believe is why it is implemented as it is. I
didn't mean that you need to do anything about this, except that right
now you must implement all 3 methods above.
我正在尝试根据 the documentation 使自定义过滤器在自定义范围内工作。
我开始认为以这种方式使用自定义过滤器存在问题,因为默认过滤器被正确调用而自定义过滤器没有被正确调用。我有的是:
ThresholdFilterCustom.java(与 ThresholdFilter 相同,创建仅用于调试):
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;
@Plugin(name = "ThresholdFilterCustom", category = "Core", elementType = "filter", printObject = true)
public final class ThresholdFilterCustom extends AbstractFilter {
private final Level level;
private ThresholdFilterCustom(Level level, Result onMatch, Result onMismatch) {
super(onMatch, onMismatch);
this.level = level;
}
public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
return filter(level);
}
@Override
public Result filter(LogEvent event) {
return filter(event.getLevel());
}
private Result filter(Level level) {
// Look here! It should always match! not even filtering!
return onMatch;
}
@Override
public String toString() {
return level.toString();
}
/**
* Create a ThresholdFilterCustom.
* @param loggerLevel The log Level.
* @param match The action to take on a match.
* @param mismatch The action to take on a mismatch.
* @return The created ThresholdFilterCustom.
*/
@PluginFactory
public static ThresholdFilterCustom createFilter(@PluginAttribute(value = "level", defaultString = "ERROR") Level level,
@PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") Result onMatch,
@PluginAttribute(value = "onMismatch", defaultString = "DENY") Result onMismatch) {
return new ThresholdFilterCustom(level, onMatch, onMismatch);
}
}
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Filters>
<ThresholdFilterCustom level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<!-- <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
</Filters>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
如果我取消评论
<!-- <ThresholdFilterCustom level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
我在控制台中没有看到 logger.debug("logmessage") 记录的消息
但如果我取消注释
<!-- <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />-->
我 看到 logger.debug("logmessage") 记录的消息,尽管它们之间的行为应该是相同的。为什么会这样?这可能是 log4j2 问题吗?
使用调试器后,我看到自定义过滤器中甚至没有调用过滤器函数,但自定义过滤器正在实例化。
如果我将它们放在记录器中,它们会正常工作。但是在上下文范围内放置它们时它们不起作用。
答案是here。
对于登陆这里的人:这里已经修复了。简而言之,似乎方法的 javadoc 混淆了。要实现上下文范围的过滤器,应该覆盖其他方法,即不是 filter(LogEvent event) 的方法。
根据 Ralph Goers 的评论:
The plugin is being properly constructed and is being called. However, you did not override all the filter methods. Most of them default to return NEUTRAL, which is what the method did in this case. It probably would make more sense to have AbstractFilter default to calling one of the other methods so that no so many methods need to be overridden.
他的另一个答案:
When the global Filters are evaluated a LogEvent has not been constructed. So if you want to only support the global filter then you need to implement all the methods that don't take a LogEvent. Likewise, to use the Filter in other places you need to only implement the method that accepts a LogEvent. Yes, I think the Javadoc has it backwards.
What I mean with regard to the default methods is that there are 3 filter methods that explicitly return NEUTRAL.
public Result filter(final Logger logger, final Level level, final
Marker marker, final Message msg,final Throwable t);
public Result filter(final Logger logger, final Level level final Marker
marker, final Object msg,final Throwable t);
public Result filter(final Logger logger, final Level level, final Marker
marker, final String msg, final Object... params);
So all 3 of these need to be implemented In a Filter such as the one you created. All the other methods that accept a Logger end up calling the method above that accepts the varargs Object (i.e. an Object array) as the last parameter. It would make sense to me that the first 2 methods should also call the third method as the default instead of returning NEUTRAL. However, that would mean losing the explicit knowledge that one of the parameters was a Throwable, which I believe is why it is implemented as it is. I didn't mean that you need to do anything about this, except that right now you must implement all 3 methods above.