[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>
+ * <turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
+ * <Key>userId</Key>
+ * <DefaultTheshold>ERROR</DefaultTheshold>
+ * <MDCValueLevelPair>
+ * <value>user1</value>
+ * <level>DEBUG</level>
+ * </MDCValueLevelPair>
+ * <MDCValueLevelPair>
+ * <value>user2</value>
+ * <level>TRACE</level>
+ * </MDCValueLevelPair>
+ * </turboFilter>
+ * </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