You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by Ceki Gülcü <ce...@qos.ch> on 2005/01/14 14:24:10 UTC

Filter Design [WAS: cvs commit: logging-log4j/src/java/org/apache/log4j/filter AndFilter.java]

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: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org