[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

noreply.ceki at qos.ch noreply.ceki at qos.ch
Fri Jul 18 15:53:00 CEST 2008


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;
+//  } 
+}


More information about the logback-dev mailing list