[logback-dev] svn commit: r1712 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic main/java/ch/qos/logback/classic/turbo test/input/joran test/java/ch/qos/logback/classic/joran

Ralph Goers Ralph.Goers at dslextreme.com
Fri Jul 18 16:21:30 CEST 2008


Thanks! I'd be interested in knowing what the concerns you have with the 
semantics are.

noreply.ceki at qos.ch wrote:
> Author: ceki
> Date: Fri Jul 18 15:53:00 2008
> New Revision: 1712
>
> Added:
>    logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/DynamicThresholdFilter.java
>    logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/MDCValueLevelPair.java
>    logback/trunk/logback-classic/src/test/input/joran/turboDynamicThreshold.xml
>    logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/joran/XConfiguratorTestX.java
> Modified:
>    logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Level.java
>
> Log:
> This patch is related to LBCLASSIC-53
>
> - This is a modified and hopefully improved version of Raph Goer's patch.
>
>   MDCLevelFilter was renamed as DynamicThresholdFilter.
>   
>   In particular, the syntax for configuring a DynamicThresholdFilter
>   is much shorter and convenient than previously. Here is an example:.
>   
> 	<turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
> 		<Key>userId</Key>
> 		<DefaultThreshold>ERROR</DefaultThreshold>
> 		<MDCValueLevelPair>
> 			<value>user1</value>
> 			<level>INFO</level>
> 		</MDCValueLevelPair>
> 		<MDCValueLevelPair>
> 			<value>user2</value>
> 			<level>TRACE</level>
> 		</MDCValueLevelPair>
>
> 	</turboFilter>
>
>   See also turboDynamicThreshold.xml.
>
>   However, I am not 100% satisfied with the semantics of
>   DynamicThresholdFilter. Expect it to change according to
>   feedback received on the mailing lists.
>
>
> Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Level.java
> ==============================================================================
> --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Level.java	(original)
> +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/Level.java	Fri Jul 18 15:53:00 2008
> @@ -144,6 +144,17 @@
>      return toLevel(sArg, Level.DEBUG);
>    }
>  
> +
> +  /**
> +   * This method exists in order to comply with Joran's valueOf convention.
> +   * @param sArg
> +   * @return
> +   */
> +  public static Level valueOf(String sArg) {
> +    return toLevel(sArg, Level.DEBUG);
> +  }
> +
> +  
>    /**
>     * Convert an integer passed as argument to a Level. If the conversion fails,
>     * then this method returns {@link #DEBUG}.
>
> Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/DynamicThresholdFilter.java
> ==============================================================================
> --- (empty file)
> +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/DynamicThresholdFilter.java	Fri Jul 18 15:53:00 2008
> @@ -0,0 +1,129 @@
> +package ch.qos.logback.classic.turbo;
> +
> +import ch.qos.logback.classic.Logger;
> +import ch.qos.logback.classic.Level;
> +import ch.qos.logback.core.spi.FilterReply;
> +import org.slf4j.Marker;
> +import org.slf4j.MDC;
> +
> +import java.util.Map;
> +import java.util.HashMap;
> +
> +/**
> + * This filter will allow you to associate threshold levels to values found 
> + * in the MDC. The threshold/value associations are looked up in MDC using
> + * a key. This key can be any value specified by the user.  
> + * 
> + * <p>TO BE DISCUSSED...
> + * 
> + * <p>This provides very efficient course grained filtering based on things like a
> + * product name or a company name that would be associated with requests as they
> + * are being processed.
> + * 
> + * The example configuration below illustrates how debug logging could be
> + * enabled for only individual users.
> + * 
> + * <pre>
> + * &lt;turboFilter class=&quot;ch.qos.logback.classic.turbo.DynamicThresholdFilter&quot;&gt;
> + *   &lt;Key&gt;userId&lt;/Key&gt;
> + *   &lt;DefaultTheshold&gt;ERROR&lt;/DefaultTheshold&gt;
> + *   &lt;MDCValueLevelPair&gt;
> + *     &lt;value&gt;user1&lt;/value&gt;
> + *     &lt;level&gt;DEBUG&lt;/level&gt;
> + *   &lt;/MDCValueLevelPair&gt;
> + *   &lt;MDCValueLevelPair&gt;
> + *     &lt;value&gt;user2&lt;/value&gt;
> + *     &lt;level&gt;TRACE&lt;/level&gt;
> + *   &lt;/MDCValueLevelPair&gt;
> + * &lt;/turboFilter&gt;
> + * </pre>
> + * 
> + * @author Raplh Goers
> + * @author Ceki Gulcu 
> + */
> +public class DynamicThresholdFilter extends TurboFilter {
> +  private Map<String, Level> valueLevelMap = new HashMap<String, Level>();
> +  private Level defaultThreshold = Level.ERROR;
> +  private String key;
> +
> +  /**
> +   * The MDC key that will be filtered against
> +   * 
> +   * @param key
> +   *                The name of the key.
> +   */
> +  public void setKey(String key) {
> +    this.key = key;
> +  }
> +
> +  /**
> +   * 
> +   * @return The name of the key being filtered
> +   */
> +  public String getKey() {
> +    return this.key;
> +  }
> +
> +  public Level getDefaultThreshold() {
> +    return defaultThreshold;
> +  }
> +
> +  public void setDefaultThreshold(Level defaultThreshold) {
> +    this.defaultThreshold = defaultThreshold;
> +  }
> +
> +  /**
> +   * Add a new MDCValuePair
> +   */
> +  public void addMDCValueLevelPair(MDCValueLevelPair mdcValueLevelPair) {
> +    if (valueLevelMap.containsKey(mdcValueLevelPair.getValue())) {
> +      addError(mdcValueLevelPair.getValue() + " has been already set");
> +    } else {
> +      valueLevelMap.put(mdcValueLevelPair.getValue(), mdcValueLevelPair
> +          .getLevel());
> +    }
> +  }
> +
> +  /**
> +   * 
> +   */
> +  @Override
> +  public void start() {
> +    if (this.key == null) {
> +      addError("No key name was specified");
> +    }
> +    super.start();
> +  }
> +
> +  /**
> +   * 
> +   * @param marker
> +   * @param logger
> +   * @param level
> +   * @param s
> +   * @param objects
> +   * @param throwable
> +   * @return
> +   */
> +  @Override
> +  public FilterReply decide(Marker marker, Logger logger, Level level,
> +      String s, Object[] objects, Throwable throwable) {
> +    String mdcValue = MDC.get(this.key);
> +    if(!isStarted()) {
> +      return FilterReply.NEUTRAL;
> +    }
> +    
> +    Level levelAssociatedWithMDCValue = null;
> +    if (mdcValue != null) {
> +      levelAssociatedWithMDCValue = valueLevelMap.get(mdcValue);
> +    }
> +    if (levelAssociatedWithMDCValue == null) {
> +      levelAssociatedWithMDCValue = defaultThreshold;
> +    }
> +    if (level.isGreaterOrEqual(levelAssociatedWithMDCValue)) {
> +      return FilterReply.NEUTRAL;
> +    } else {
> +      return FilterReply.DENY;
> +    }
> +  }
> +}
>
> Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/MDCValueLevelPair.java
> ==============================================================================
> --- (empty file)
> +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/turbo/MDCValueLevelPair.java	Fri Jul 18 15:53:00 2008
> @@ -0,0 +1,31 @@
> +package ch.qos.logback.classic.turbo;
> +
> +import ch.qos.logback.classic.Level;
> +
> +
> +/**
> + * Bean pairing an MDC value with a log level.
> + * 
> + * @author Raplh Goers
> + * @author Ceki Gulcu 
> + */
> +public class MDCValueLevelPair {
> +  private String value;
> +  private Level level;
> +
> +  public String getValue() {
> +    return value;
> +  }
> +
> +  public void setValue(String name) {
> +    this.value = name;
> +  }
> +
> +  public Level getLevel() {
> +    return level;
> +  }
> +
> +  public void setLevel(Level level) {
> +    this.level = level;
> +  }
> +}
>
> Added: logback/trunk/logback-classic/src/test/input/joran/turboDynamicThreshold.xml
> ==============================================================================
> --- (empty file)
> +++ logback/trunk/logback-classic/src/test/input/joran/turboDynamicThreshold.xml	Fri Jul 18 15:53:00 2008
> @@ -0,0 +1,29 @@
> +<?xml version="1.0" encoding="UTF-8" ?>
> +<!DOCTYPE configuration>
> +
> +<configuration>
> +
> +	<turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
> +		<Key>userId</Key>
> +		<DefaultThreshold>ERROR</DefaultThreshold>
> +		<MDCValueLevelPair>
> +			<value>user1</value>
> +			<level>INFO</level>
> +		</MDCValueLevelPair>
> +		<MDCValueLevelPair>
> +			<value>user2</value>
> +			<level>TRACE</level>
> +		</MDCValueLevelPair>
> +
> +	</turboFilter>
> +
> +
> +	<appender name="LIST"
> +		class="ch.qos.logback.core.read.ListAppender">
> +	</appender>
> +
> +	<root>
> +		<level value="DEBUG" />
> +		<appender-ref ref="LIST" />
> +	</root>
> +</configuration>
>
> Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/joran/XConfiguratorTestX.java
> ==============================================================================
> --- (empty file)
> +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/joran/XConfiguratorTestX.java	Fri Jul 18 15:53:00 2008
> @@ -0,0 +1,62 @@
> +/**
> + * LOGBack: the generic, reliable, fast and flexible logging framework.
> + *
> + * Copyright (C) 1999-2006, QOS.ch
> + *
> + * This library is free software, you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License as
> + * published by the Free Software Foundation.
> + */
> +package ch.qos.logback.classic.joran;
> +
> +import junit.framework.TestCase;
> +
> +import org.slf4j.MDC;
> +
> +import ch.qos.logback.classic.Logger;
> +import ch.qos.logback.classic.LoggerContext;
> +import ch.qos.logback.classic.spi.LoggingEvent;
> +import ch.qos.logback.classic.util.TeztConstants;
> +import ch.qos.logback.core.joran.spi.JoranException;
> +import ch.qos.logback.core.read.ListAppender;
> +import ch.qos.logback.core.util.StatusPrinter;
> +
> +public class XConfiguratorTestX extends TestCase {
> +
> +  public XConfiguratorTestX(String name) {
> +    super(name);
> +  }
> +  
> +  public void testSimpleList() throws JoranException { 
> +    JoranConfigurator jc = new JoranConfigurator();
> +    LoggerContext loggerContext = new LoggerContext(); 
> +    jc.setContext(loggerContext);
> +    jc.doConfigure(TeztConstants.TEST_DIR_PREFIX + "input/joran/turboDynamicThreshold.xml");
> +
> +    StatusPrinter.print(loggerContext.getStatusManager());
> +  
> +    Logger logger = loggerContext.getLogger(this.getClass().getName());
> +    Logger root = loggerContext.getLogger(LoggerContext.ROOT_NAME);
> +    ListAppender listAppender = (ListAppender) root.getAppender("LIST");
> +    assertEquals(0, listAppender.list.size());
> +   
> +    // this one should be denied
> +    MDC.put("userId", "user1");
> +    logger.debug("hello user1");
> +    // this one should log
> +    MDC.put("userId", "user2");
> +    logger.debug("hello user2"); 
> +    
> +    assertEquals(1, listAppender.list.size());
> +    LoggingEvent le = (LoggingEvent) listAppender.list.get(0);
> +    assertEquals("hello user2", le.getMessage());
> +  }
> +  
> + 
> +//  public static Test suite() {
> +//    TestSuite suite = new TestSuite();
> +//    suite.addTestSuite(XConfiguratorTest.class);
> +//    //suite.addTest(new JoranConfiguratorTest("testEvaluatorFilter"));
> +//    return suite;
> +//  } 
> +}
> _______________________________________________
> logback-dev mailing list
> logback-dev at qos.ch
> http://qos.ch/mailman/listinfo/logback-dev
>   


More information about the logback-dev mailing list