Scott,
For starters, although I do not feel strongly either way, instead of AndFilter and OrFilter, I propose the names Conjunction and Disjunction. The latter names emphasize their purpose, that is, the logical grouping of filters. Most people will need to stop and think about what conjunction and disjunction actually mean, which is not necessarily bad in itself.
I think it is high time to improve the current filter design by separating the filter plumbing from selection criteria.
To improve the design, I propose a basic Filter class which would delegate its match/mismatch logic to some other object. Thus the Filter class would provide the plumbing to chaining filters and returning the correct value (ACCEPT, DENY, NEUTRAL) depending on whether a given event matched some criterion or not.
// new class
public interface Criterion {
// has the event matched the criterion?
boolean match(LoggingEvent event);
}// remains the same
abstract class Filter {
public abstract int decide(LoggingEvent event); public void setNext(Filter next) {
this.next = next; public Filter getNext() {
return next;
}
}
abstract class LogicBase extends Filter {
Criterion criterion ; int onMatch = Filter.NEUTRAL; int onMismatch = Filter.NEUTRAL;
public void activateOptions() { if(criterion == null) { throw new IllegalStateException("criterion required"); } }
public void setOnMatch(String decision) {
if("NEUTRAL".equalsIgnoreCase(decision) {
onMatch = NEUTRAL;
} else if("ACCEPT".equalsIgnoreCase(decision)) {
onMatch = ACCEPT;
} else if("DENY".equalsIgnoreCase(decision)) {
onMatch = DENY;
}
} public void setOnMismatch(String decision) {
if("NEUTRAL".equalsIgnoreCase(decision) {
onMismatch = NEUTRAL;
} else if("ACCEPT".equalsIgnoreCase(decision)) {
onMismatch = ACCEPT;
} else if("DENY".equalsIgnoreCase(decision)) {
onMismatch = DENY;
}
} public void setCriterion(final Criterion criterion) {
this.criterion = criterion;
} public int decide(LoggingEvent event) {
boolean match = criterion.match(event);
if(match) {
return onMatch;
} else {
return onMismatch;
}
}
}We would keep the filters which existed in log4j 1.2.8 for backward compatibility. New filters would be written in terms of criteria, for example:
<filter class="org.apache.log4j.filter.LogicBase">
<criterion class="org.apache.log4j.filter.StringMatch">
<param name="StringToMatch" value="hello"/>
</criterion>
<param name="onMatch" value="ACCEPT"/>
</filter>would be equivalent to
<filter class="org.apache.log4j.filter.StringMatcFilter"> <param name="StringToMatch" value="hello"/> <param name="AcceptOnMatch" value="true"/> </filter>
Composite criteria could be written as:
<filter class="org.apache.log4j.filter.LogicBase">
<criterion class="org.apache.log4j.filter.Conjuction">
<nestedCriterion class="org.apache.log4j.filter.StringMatch">
<param name="StringToMatch" value="hello"/>
</nestedCriterion>
<nestedCriterion class="org.apache.log4j.filter.LevelMatch">
<param name="LevelToMatch" value="INFO"/>
</nestedCriterion>
<nestedCriterion class="org.apache.log4j.filter.LoggerMatch">
<param name="LoggerToMatch" value="com.wombat"/>
</nestedCriterion>
</criterion>
<param name="onMatch" value="DENY"/>
</filter>(The above filter denies events of level INFO generated by the "org.womcat" logger containing the string "hello". If these criteria are not met, that is on mismatch, the the filter returns the default value of NEUTRAL.)
If criteria need to be multiply nested, than we could write (dropping the nestedCriterion distinction):
<filter class="org.apache.log4j.filter.LogicBase">
<criterion class="org.apache.log4j.filter.Conjuction">
<criterion class="org.apache.log4j.filter.StringMatch">
<param name="StringToMatch" value="hello"/>
</criterion> <criterion class="org.apache.log4j.filter.LevelMatch">
<param name="LevelToMatch" value="INFO"/>
</criterion> <criterion class="org.apache.log4j.filter.Disjunction">
<criterion class="org.apache.log4j.filter.LoggerMatch">
<param name="LoggerToMatch" value="com.wombat"/>
</criterion>
<criterion class="org.apache.log4j.filter.LoggerMatch">
<param name="LoggerToMatch" value="com.foo"/>
</criterion>
</criterion></criterion> <param name="onMatch" value="DENY"/> </filter>
(The above filter denies events of level INFO generated by the "org.womcat" or "org.foo" loggers containing the string "hello". If these criteria are not met, that is on mismatch, the filter returns the default value of NEUTRAL.)
As mentioned previously, the existing filters would remain, perhaps marked as deprecated. They would be implemented in terms of fixed criteria classes.
Having said all this, the similarity between Criterion and Rule (in o.a.l.rule package) is too striking to be ignored... :-)
Comments?
At 08:30 AM 1/14/2005, Scott Deboy wrote:
I've been thinking about implementing filter as an action.
An example:
appender x filter andfilter1 nested filter levelmatch1 ??? filter or nested filter andfilter2 nested filter levelmatch2 nested filter stringmatch2 ...
What name should the ??? node use? nestedfilter or filter?
If the filter node name is only used for the immediate children of appender, it seems less useful than some other convention.
Maybe if andFilter was what used a new node name: containingfilter or something like that?
just looking for clarification
Scott
-- Ceki G�lc�
The complete log4j manual: http://www.qos.ch/log4j/
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
