logback-dev
Threads by month
- ----- 2025 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
March 2010
- 11 participants
- 188 discussions

[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. release_0.9.19-7-g199e8d6
by git-noreply@pixie.qos.ch 29 Mar '10
by git-noreply@pixie.qos.ch 29 Mar '10
29 Mar '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 199e8d6d8218c1bf526c224e867891110ac0ecbb (commit)
from 2391b73837b528d78505a0b3a339b533b791d283 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=199e8d6d8218c1bf526c224e…
http://github.com/ceki/logback/commit/199e8d6d8218c1bf526c224e867891110ac0e…
commit 199e8d6d8218c1bf526c224e867891110ac0ecbb
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Mon Mar 29 22:54:58 2010 +0200
- initial impl of if-then-else support in logback-classes
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java b/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java
index 9bc0624..765498a 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java
@@ -29,6 +29,9 @@ import ch.qos.logback.core.joran.JoranConfiguratorBase;
import ch.qos.logback.core.joran.action.AppenderRefAction;
import ch.qos.logback.core.joran.action.IncludeAction;
import ch.qos.logback.core.joran.action.NOPAction;
+import ch.qos.logback.core.joran.conditional.ElseAction;
+import ch.qos.logback.core.joran.conditional.IfAction;
+import ch.qos.logback.core.joran.conditional.ThenAction;
import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
import ch.qos.logback.core.joran.spi.Pattern;
import ch.qos.logback.core.joran.spi.RuleStore;
@@ -68,7 +71,14 @@ public class JoranConfigurator extends JoranConfiguratorBase {
new AppenderRefAction());
rs.addRule(new Pattern("configuration/root/appender-ref"),
new AppenderRefAction());
-
+
+ // add if-then-else support
+ rs.addRule(new Pattern("*/if"), new IfAction());
+ rs.addRule(new Pattern("*/if/then"), new ThenAction());
+ rs.addRule(new Pattern("*/if/then/*"), new NOPAction());
+ rs.addRule(new Pattern("*/if/else"), new ElseAction());
+ rs.addRule(new Pattern("*/if/else/*"), new NOPAction());
+
// add jmxConfigurator only if we have JMX available.
// If running under JDK 1.4 (retrotranslateed logback) then we
// might not have JMX.
diff --git a/logback-classic/src/test/input/joran/conditional/conditionalConsoleApp.xml b/logback-classic/src/test/input/joran/conditional/conditionalConsoleApp.xml
new file mode 100644
index 0000000..52e2e64
--- /dev/null
+++ b/logback-classic/src/test/input/joran/conditional/conditionalConsoleApp.xml
@@ -0,0 +1,29 @@
+
+<configuration>
+
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>${randomOutputDir}/conditional.log</file>
+ <encoder>
+ <pattern>%d %-5level %logger{35} - %msg %n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="ERROR">
+ <appender-ref ref="FILE" />
+ </root>
+
+
+ <if condition='property("HOSTNAME").contains("${aHost}")'>
+ <then>
+ <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d %-5level %logger{35} - %msg %n</pattern>
+ </encoder>
+ </appender>
+ <root>
+ <appender-ref ref="CON" />
+ </root>
+ </then>
+ </if>
+
+</configuration>
\ No newline at end of file
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java
index 07fa46f..6512023 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/joran/JoranConfiguratorTest.java
@@ -307,8 +307,10 @@ public class JoranConfiguratorTest {
assertEquals("UTF-8", encoder.getCharset().displayName());
StatusChecker checker = new StatusChecker(loggerContext);
- assertTrue(checker.isErrorFree());
-
+ assertTrue(checker.isErrorFree());
}
+
+
+
}
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/joran/conditional/ConditionalTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/joran/conditional/ConditionalTest.java
new file mode 100644
index 0000000..0c1329c
--- /dev/null
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/joran/conditional/ConditionalTest.java
@@ -0,0 +1,77 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under either
+ * the terms of the Eclipse Public License v1.0 as published by the Eclipse
+ * Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ */
+package ch.qos.logback.classic.joran.conditional;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import ch.qos.logback.classic.ClassicTestConstants;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.ConsoleAppender;
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.CoreTestConstants;
+import ch.qos.logback.core.util.StatusPrinter;
+
+
+public class ConditionalTest {
+
+ LoggerContext context = new LoggerContext();
+ Logger root = context.getLogger(Logger.ROOT_LOGGER_NAME);
+
+
+ int diff = RandomUtil.getPositiveInt();
+ String randomOutputDir = CoreTestConstants.OUTPUT_DIR_PREFIX + diff + "/";
+
+ @Before
+ public void setUp() throws UnknownHostException {
+ context.setName("c"+diff);
+ context.putProperty("randomOutputDir", randomOutputDir);
+ InetAddress localhost = InetAddress.getLocalHost();
+ context.putProperty("aHost", localhost.getCanonicalHostName());
+ }
+
+
+ void configure(String file) throws JoranException {
+ JoranConfigurator jc = new JoranConfigurator();
+ jc.setContext(context);
+ jc.doConfigure(file);
+ }
+
+ @Test
+ public void conditionalConsoleApp() throws JoranException, IOException,
+ InterruptedException {
+
+ String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX
+ + "conditional/conditionalConsoleApp.xml";
+ configure(configFileAsStr);
+ FileAppender fileAppender = (FileAppender) root.getAppender("FILE");
+ assertNotNull(fileAppender);
+
+ ConsoleAppender consoleAppender = (ConsoleAppender) root.getAppender("CON");
+ assertNotNull(consoleAppender);
+ StatusPrinter.printIfErrorsOccured(context);
+
+
+ }
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java b/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
index c66e5b0..2bb626a 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
@@ -29,7 +29,6 @@ import ch.qos.logback.core.joran.action.ParamAction;
import ch.qos.logback.core.joran.action.PropertyAction;
import ch.qos.logback.core.joran.action.StatusListenerAction;
import ch.qos.logback.core.joran.action.TimestampAction;
-import ch.qos.logback.core.joran.conditional.IfAction;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.joran.spi.Interpreter;
import ch.qos.logback.core.joran.spi.Pattern;
@@ -67,10 +66,6 @@ abstract public class JoranConfiguratorBase extends GenericConfigurator {
rs.addRule(new Pattern("configuration/timestamp"),
new TimestampAction());
- rs.addRule(new Pattern("*/if"),
- new IfAction());
-
-
// the contextProperty pattern is deprecated. It is undocumented
// and will be dropped in future versions of logback
rs.addRule(new Pattern("configuration/contextProperty"),
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
index 23eaf7c..513d350 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
@@ -23,9 +23,11 @@ public class IfAction extends Action {
throws ActionException {
ic.pushObject(this);
+
Condition condition = null;
String conditionAttribute = attributes.getValue(CONDITION_ATTR);
if (!OptionHelper.isEmpty(conditionAttribute)) {
+ conditionAttribute = OptionHelper.substVars(conditionAttribute, context);
PropertyEvalScriptBuilder pesb = new PropertyEvalScriptBuilder();
pesb.setContext(context);
try {
-----------------------------------------------------------------------
Summary of changes:
.../logback/classic/joran/JoranConfigurator.java | 12 +++-
.../joran/conditional/conditionalConsoleApp.xml | 29 ++++++++
.../classic/joran/JoranConfiguratorTest.java | 6 +-
.../classic/joran/conditional/ConditionalTest.java | 77 ++++++++++++++++++++
.../logback/core/joran/JoranConfiguratorBase.java | 5 --
.../logback/core/joran/conditional/IfAction.java | 2 +
6 files changed, 123 insertions(+), 8 deletions(-)
create mode 100644 logback-classic/src/test/input/joran/conditional/conditionalConsoleApp.xml
create mode 100644 logback-classic/src/test/java/ch/qos/logback/classic/joran/conditional/ConditionalTest.java
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0

[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. release_0.9.19-6-g2391b73
by git-noreply@pixie.qos.ch 29 Mar '10
by git-noreply@pixie.qos.ch 29 Mar '10
29 Mar '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 2391b73837b528d78505a0b3a339b533b791d283 (commit)
from 1a86d32aba6e17f21c242999dad27916e051ee3d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=2391b73837b528d78505a0b3…
http://github.com/ceki/logback/commit/2391b73837b528d78505a0b3a339b533b791d…
commit 2391b73837b528d78505a0b3a339b533b791d283
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Mon Mar 29 20:06:23 2010 +0200
- added missing files for if-then-else support in Joran (this is still ongoing work).
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/Condition.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/Condition.java
new file mode 100644
index 0000000..344ffcf
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/Condition.java
@@ -0,0 +1,18 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under either
+ * the terms of the Eclipse Public License v1.0 as published by the Eclipse
+ * Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ */
+package ch.qos.logback.core.joran.conditional;
+
+public interface Condition {
+ public boolean evaluate();
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ElseAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ElseAction.java
new file mode 100644
index 0000000..63ede3f
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ElseAction.java
@@ -0,0 +1,44 @@
+package ch.qos.logback.core.joran.conditional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.event.InPlayListener;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.InterpretationContext;
+
+public class ElseAction extends Action implements InPlayListener {
+
+ List<SaxEvent> saxEventList;
+
+ @Override
+ public void begin(InterpretationContext ic, String name, Attributes attributes)
+ throws ActionException {
+ saxEventList = new ArrayList<SaxEvent>();
+ ic.addInPlayListener(this);
+ }
+
+ @Override
+ public void end(InterpretationContext ic, String name) throws ActionException {
+ ic.removeInPlayListener(this);
+ Object o = ic.peekObject();
+ if (o instanceof IfAction) {
+ IfAction ifAction = (IfAction) o;
+ removeFirstLastFromList();
+ ifAction.setElseSaxEventList(saxEventList);
+ }
+ }
+
+ public void inPlay(SaxEvent event) {
+ saxEventList.add(event);
+ }
+
+ void removeFirstLastFromList() {
+ saxEventList.remove(0);
+ saxEventList.remove(saxEventList.size() - 1);
+ }
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
new file mode 100644
index 0000000..23eaf7c
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
@@ -0,0 +1,90 @@
+package ch.qos.logback.core.joran.conditional;
+
+import java.util.List;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.InterpretationContext;
+import ch.qos.logback.core.joran.spi.Interpreter;
+import ch.qos.logback.core.util.OptionHelper;
+
+public class IfAction extends Action {
+ private static final String CONDITION_ATTR = "condition";
+
+ Boolean boolResult;
+ List<SaxEvent> thenSaxEventList;
+ List<SaxEvent> elseSaxEventList;
+
+ @Override
+ public void begin(InterpretationContext ic, String name, Attributes attributes)
+ throws ActionException {
+
+ ic.pushObject(this);
+ Condition condition = null;
+ String conditionAttribute = attributes.getValue(CONDITION_ATTR);
+ if (!OptionHelper.isEmpty(conditionAttribute)) {
+ PropertyEvalScriptBuilder pesb = new PropertyEvalScriptBuilder();
+ pesb.setContext(context);
+ try {
+ condition = pesb.build(conditionAttribute);
+ } catch (Exception e) {
+ addError("Faield to parse condition ["+conditionAttribute+"]", e);
+ }
+
+ if(condition!=null) {
+ boolResult = condition.evaluate();
+ }
+
+ }
+ }
+
+
+ @Override
+ public void end(InterpretationContext ic, String name) throws ActionException {
+
+ Object o = ic.peekObject();
+ if (o == null) {
+ throw new IllegalStateException("Unexpected null object on stack");
+ }
+ if (!(o instanceof IfAction)) {
+ throw new IllegalStateException("Unexpected object of type ["
+ + o.getClass() + "] on stack");
+ }
+
+ if (o != this) {
+ throw new IllegalStateException(
+ "IfAction different then current one on stack");
+ }
+ ic.popObject();
+
+ if (boolResult == null) {
+ addError("Failed to determine \"if then else\" result");
+ return;
+ }
+
+ Interpreter interpreter = ic.getJoranInterpreter();
+ List<SaxEvent> listToPlay = thenSaxEventList;
+ if (!boolResult) {
+ listToPlay = elseSaxEventList;
+ }
+
+ if (interpreter.pattern.peekLast().equals("if")) {
+ interpreter.pattern.pop();
+ interpreter.play(listToPlay);
+ interpreter.pattern.push("if");
+ }
+
+ }
+
+ public void setThenSaxEventList(List<SaxEvent> thenSaxEventList) {
+ this.thenSaxEventList = thenSaxEventList;
+ }
+
+ public void setElseSaxEventList(List<SaxEvent> elseSaxEventList) {
+ this.elseSaxEventList = elseSaxEventList;
+ }
+
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/MapWrapperForScripts.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/MapWrapperForScripts.java
new file mode 100644
index 0000000..e20a9ec
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/MapWrapperForScripts.java
@@ -0,0 +1,57 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under either
+ * the terms of the Eclipse Public License v1.0 as published by the Eclipse
+ * Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ */
+package ch.qos.logback.core.joran.conditional;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapWrapperForScripts {
+ public Map map = new HashMap<String, String>();
+ public String name;
+
+
+ public void setMap(Map map) {
+ this.map = map;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isNull(String k) {
+ Object o = map.get(k);
+ if (o instanceof String) {
+ return false;
+ }
+ return (System.getProperty(k) == null);
+ }
+
+ public String p(String k) {
+ return property(k);
+ }
+
+ public String property(String k) {
+ Object o = map.get(k);
+ if (o instanceof String) {
+ return (String) o;
+ }
+ String v = System.getProperty(k);
+ if(v != null) {
+ return v;
+ }
+ System.getProperties();
+ return "";
+ }
+
+
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilder.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilder.java
new file mode 100644
index 0000000..e29c414
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilder.java
@@ -0,0 +1,49 @@
+package ch.qos.logback.core.joran.conditional;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.codehaus.janino.ClassBodyEvaluator;
+import org.codehaus.janino.CompileException;
+import org.codehaus.janino.Parser.ParseException;
+import org.codehaus.janino.Scanner.ScanException;
+import org.junit.Before;
+
+import ch.qos.logback.core.spi.ContextAwareBase;
+
+public class PropertyEvalScriptBuilder extends ContextAwareBase {
+
+ private static String SCRIPT_PREFIX = ""
+ + "public boolean evaluate() { return ";
+ private static String SCRIPT_SUFFIX = "" + "; }";
+
+ static String SCRIPT = ""
+ + "public boolean eval() { return p(\"Ka\").equals(\"Va\"); }";
+
+ Map<String, String> map = new HashMap<String, String>();
+
+ @Before
+ public Condition build(String script) throws IllegalAccessException,
+ CompileException, ParseException, ScanException, InstantiationException,
+ SecurityException, NoSuchMethodException, IllegalArgumentException,
+ InvocationTargetException {
+
+ ClassBodyEvaluator cbe = new ClassBodyEvaluator();
+ cbe.setImplementedTypes(new Class[] { Condition.class });
+ cbe.setExtendedType(MapWrapperForScripts.class);
+ cbe.cook(SCRIPT_PREFIX + script + SCRIPT_SUFFIX);
+
+ Class<?> clazz = cbe.getClazz();
+ Condition instance = (Condition) clazz.newInstance();
+ Method setMapMethod = clazz.getMethod("setMap", Map.class);
+ setMapMethod.invoke(instance, context.getCopyOfPropertyMap());
+
+ Method setNameMethod = clazz.getMethod("setName", String.class);
+ setNameMethod.invoke(instance, context.getName());
+
+ return instance;
+ }
+
+}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ThenAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ThenAction.java
new file mode 100644
index 0000000..5e5f99b
--- /dev/null
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ThenAction.java
@@ -0,0 +1,46 @@
+package ch.qos.logback.core.joran.conditional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.event.InPlayListener;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.InterpretationContext;
+
+public class ThenAction extends Action implements InPlayListener {
+
+ List<SaxEvent> eventList;
+
+ @Override
+ public void begin(InterpretationContext ic, String name, Attributes attributes)
+ throws ActionException {
+ eventList = new ArrayList<SaxEvent>();
+ ic.addInPlayListener(this);
+ }
+
+ @Override
+ public void end(InterpretationContext ic, String name) throws ActionException {
+ ic.removeInPlayListener(this);
+ Object o = ic.peekObject();
+ if (o instanceof IfAction) {
+ IfAction ifAction = (IfAction) o;
+ removeFirstLastFromList();
+ ifAction.setThenSaxEventList(eventList);
+ } else {
+ throw new IllegalStateException("Missing IfAction on top of stack");
+ }
+ }
+
+ public void inPlay(SaxEvent event) {
+ eventList.add(event);
+ }
+
+ void removeFirstLastFromList() {
+ eventList.remove(0);
+ eventList.remove(eventList.size() - 1);
+ }
+}
diff --git a/logback-core/src/test/input/joran/conditional/if0.xml b/logback-core/src/test/input/joran/conditional/if0.xml
new file mode 100644
index 0000000..0273e59
--- /dev/null
+++ b/logback-core/src/test/input/joran/conditional/if0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<x>
+ <if condition='p("Ki1").equals("Val1")'>
+ <then>
+ <inc increment="1"/>
+ </then>
+ <else>
+ <inc increment="1"/>
+ <inc increment="1"/>
+ </else>
+ </if>
+</x>
diff --git a/logback-core/src/test/input/joran/conditional/if2.xml b/logback-core/src/test/input/joran/conditional/if2.xml
new file mode 100644
index 0000000..bc70e1f
--- /dev/null
+++ b/logback-core/src/test/input/joran/conditional/if2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<x>
+ <if class="">
+ <a>asd</a>
+ <then>
+ <inc increment="1"/>
+ </then>
+ <else>
+ <inc increment="1"/>
+ <inc increment="1"/>
+ </else>
+ </if>
+</x>
diff --git a/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/IfThenElseTest.java b/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/IfThenElseTest.java
new file mode 100644
index 0000000..bf9aa89
--- /dev/null
+++ b/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/IfThenElseTest.java
@@ -0,0 +1,88 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under either
+ * the terms of the Eclipse Public License v1.0 as published by the Eclipse
+ * Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ */
+package ch.qos.logback.core.joran.conditional;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.ContextBase;
+import ch.qos.logback.core.joran.TrivialConfigurator;
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.action.NOPAction;
+import ch.qos.logback.core.joran.action.ext.IncAction;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.joran.spi.Pattern;
+import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.CoreTestConstants;
+import ch.qos.logback.core.util.StatusPrinter;
+
+public class IfThenElseTest {
+
+ Context context = new ContextBase();
+ TrivialConfigurator tc;
+ int diff = RandomUtil.getPositiveInt();
+ static final String CONDITIONAL_DIR_PREFIX = CoreTestConstants.JORAN_INPUT_PREFIX
+ + "conditional/";
+
+
+ @Before
+ public void setUp() throws Exception {
+ HashMap<Pattern, Action> rulesMap = new HashMap<Pattern, Action>();
+ rulesMap.put(new Pattern("x"), new NOPAction());
+ rulesMap.put(new Pattern("x/inc"), new IncAction());
+ rulesMap.put(new Pattern("*/if"), new IfAction());
+ rulesMap.put(new Pattern("*/if/then"), new ThenAction());
+ rulesMap.put(new Pattern("*/if/then/*"), new NOPAction());
+ rulesMap.put(new Pattern("*/if/else"), new ElseAction());
+ rulesMap.put(new Pattern("*/if/else/*"), new NOPAction());
+
+ tc = new TrivialConfigurator(rulesMap);
+ tc.setContext(context);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ IncAction.reset();
+ }
+
+ @Test
+ public void if0_Then() throws JoranException {
+ context.putProperty("Ki1", "Val1");
+ tc.doConfigure(CONDITIONAL_DIR_PREFIX+"if0.xml");
+ verifyConfig(1);
+ }
+
+ @Test
+ public void if0_Else() throws JoranException {
+ tc.doConfigure(CONDITIONAL_DIR_PREFIX+"if0.xml");
+ StatusPrinter.print(context);
+ verifyConfig(2);
+ }
+
+
+ void verifyConfig(int expected) {
+ assertEquals(expected, IncAction.beginCount);
+ assertEquals(expected, IncAction.endCount);
+ }
+
+
+
+}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilderTest.java b/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilderTest.java
new file mode 100644
index 0000000..aab2646
--- /dev/null
+++ b/logback-core/src/test/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilderTest.java
@@ -0,0 +1,74 @@
+package ch.qos.logback.core.joran.conditional;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.ContextBase;
+import ch.qos.logback.core.testUtil.RandomUtil;
+
+public class PropertyEvalScriptBuilderTest {
+
+
+ Context context = new ContextBase();
+ PropertyEvalScriptBuilder pesb = new PropertyEvalScriptBuilder();
+ int diff = RandomUtil.getPositiveInt();
+
+ @Before
+ public void setUp() {
+ context.setName("c"+diff);
+ pesb.setContext(context);
+ }
+
+ @Test
+ public void existing() throws Exception {
+ String k = "ka"+diff;
+ context.putProperty("ka"+diff, "va");
+ Condition condition = pesb.build("p(\""+k+"\").contains(\"va\")");
+ assertNotNull(condition);
+ assertTrue(condition.evaluate());
+ }
+
+ @Test
+ public void isNullForExisting() throws Exception {
+ String k = "ka"+diff;
+ context.putProperty("ka"+diff, "va");
+ Condition condition = pesb.build("isNull(\""+k+"\")");
+ assertNotNull(condition);
+ assertFalse(condition.evaluate());
+ }
+
+
+ @Test
+ public void inexistentProperty() throws Exception {
+ String k = "ka"+diff;
+ Condition condition = pesb.build("p(\""+k+"\").contains(\"va\")");
+ assertNotNull(condition);
+ assertFalse(condition.evaluate());
+ }
+
+ @Test
+ public void isNullForInexistent() throws Exception {
+ String k = "ka"+diff;
+ Condition condition = pesb.build("isNull(\""+k+"\")");
+ assertNotNull(condition);
+ assertTrue(condition.evaluate());
+ }
+
+ @Test
+ public void nameOK() throws Exception {
+ Condition condition = pesb.build("name.contains(\""+context.getName()+"\")");
+ assertNotNull(condition);
+ assertTrue(condition.evaluate());
+ }
+
+ @Test
+ public void wrongName() throws Exception {
+ Condition condition = pesb.build("name.contains(\"x\")");
+ assertNotNull(condition);
+ assertFalse(condition.evaluate());
+ }
+
+}
-----------------------------------------------------------------------
Summary of changes:
.../logback/core/joran/conditional/Condition.java | 10 +--
.../logback/core/joran/conditional/ElseAction.java | 44 ++++++++++
.../logback/core/joran/conditional/IfAction.java | 90 ++++++++++++++++++++
.../joran/conditional/MapWrapperForScripts.java | 57 ++++++++++++
.../conditional/PropertyEvalScriptBuilder.java | 49 +++++++++++
.../logback/core/joran/conditional/ThenAction.java | 46 ++++++++++
.../src/test/input/joran/conditional/if0.xml | 13 +++
.../src/test/input/joran/conditional/if2.xml | 14 +++
.../core/joran/conditional/IfThenElseTest.java | 88 +++++++++++++++++++
.../conditional/PropertyEvalScriptBuilderTest.java | 74 ++++++++++++++++
10 files changed, 479 insertions(+), 6 deletions(-)
copy logback-classic/src/main/java/ch/qos/logback/classic/db/names/DBNameResolver.java => logback-core/src/main/java/ch/qos/logback/core/joran/conditional/Condition.java (71%)
create mode 100644 logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ElseAction.java
create mode 100644 logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
create mode 100644 logback-core/src/main/java/ch/qos/logback/core/joran/conditional/MapWrapperForScripts.java
create mode 100644 logback-core/src/main/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilder.java
create mode 100644 logback-core/src/main/java/ch/qos/logback/core/joran/conditional/ThenAction.java
create mode 100644 logback-core/src/test/input/joran/conditional/if0.xml
create mode 100644 logback-core/src/test/input/joran/conditional/if2.xml
create mode 100644 logback-core/src/test/java/ch/qos/logback/core/joran/conditional/IfThenElseTest.java
create mode 100644 logback-core/src/test/java/ch/qos/logback/core/joran/conditional/PropertyEvalScriptBuilderTest.java
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0

[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. release_0.9.19-5-g1a86d32
by git-noreply@pixie.qos.ch 29 Mar '10
by git-noreply@pixie.qos.ch 29 Mar '10
29 Mar '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 1a86d32aba6e17f21c242999dad27916e051ee3d (commit)
from 39d30d0f0028dfd75177a298231d086b4dddbb73 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=1a86d32aba6e17f21c242999…
http://github.com/ceki/logback/commit/1a86d32aba6e17f21c242999dad27916e051e…
commit 1a86d32aba6e17f21c242999dad27916e051ee3d
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Mon Mar 29 20:00:58 2010 +0200
- added copyright notice on SQL scripts for various DB's
- started to add if/then/else support in Joran
- removed duplicate logback-examples/src/main/java/chapters/appenders/onJoran/ folder
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/db2.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/db2.sql
index 6e6d9b8..4fedc9d 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/db2.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/db2.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.access.db.DBAppender
#
# It is intended for IBM DB2 databases.
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/deleteTables.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/deleteTables.sql
deleted file mode 100644
index bd7c256..0000000
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/deleteTables.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-
-delete from access_event_property;
-delete from access_event;
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/hsqldb.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/hsqldb.sql
index 714630c..459a16b 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/hsqldb.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/hsqldb.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.access.db.DBAppender
#
# It is intended for HSQL databases.
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/msSQLServer.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/msSQLServer.sql
index d3d74ed..7524ad3 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/msSQLServer.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/msSQLServer.sql
@@ -1,3 +1,9 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
-- This SQL script creates the required tables by ch.qos.logback.access.db.DBAppender
--
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/mysql.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/mysql.sql
index 70bb9f6..ca4687d 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/mysql.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/mysql.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.access.db.DBAppender.
#
# It is intended for MySQL databases. It has been tested on MySQL 5.0.22 with
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/oracle.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/oracle.sql
index 9533d1e..a47dc22 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/oracle.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/oracle.sql
@@ -1,3 +1,9 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
-- This SQL script creates the required tables by ch.qos.logback.access.db.DBAppender
--
-- It is intended for Oracle databases.
diff --git a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/postgresql.sql b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/postgresql.sql
index ba5cce7..f0e3430 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/db/dialect/postgresql.sql
+++ b/logback-access/src/main/java/ch/qos/logback/access/db/dialect/postgresql.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
#
# It is intended for PostgreSQL databases.
diff --git a/logback-access/src/main/java/ch/qos/logback/access/sift/SiftAction.java b/logback-access/src/main/java/ch/qos/logback/access/sift/SiftAction.java
index a5735dd..496f788 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/sift/SiftAction.java
+++ b/logback-access/src/main/java/ch/qos/logback/access/sift/SiftAction.java
@@ -28,16 +28,16 @@ public class SiftAction extends Action implements InPlayListener {
List<SaxEvent> seList;
@Override
- public void begin(InterpretationContext ec, String name, Attributes attributes)
+ public void begin(InterpretationContext ic, String name, Attributes attributes)
throws ActionException {
seList = new ArrayList<SaxEvent>();
- ec.addInPlayListener(this);
+ ic.addInPlayListener(this);
}
@Override
- public void end(InterpretationContext ec, String name) throws ActionException {
- ec.removeInPlayListener(this);
- Object o = ec.peekObject();
+ public void end(InterpretationContext ic, String name) throws ActionException {
+ ic.removeInPlayListener(this);
+ Object o = ic.peekObject();
if (o instanceof SiftingAppender) {
SiftingAppender siftingAppender = (SiftingAppender) o;
AppenderFactory appenderFactory = new AppenderFactory(seList, siftingAppender.getDiscriminatorKey());
diff --git a/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java b/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java
index 4c39e27..d19ddbb 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java
+++ b/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java
@@ -53,7 +53,8 @@ import ch.qos.logback.core.util.StatusPrinter;
* This class is an implementation of tomcat's Valve interface, by extending
* ValveBase.
*
- * <p>For more information on using LogbackValve please refer to the online
+ * <p>
+ * For more information on using LogbackValve please refer to the online
* documentation on <a
* href="http://logback.qos.ch/access.html#tomcat">logback-acces and tomcat</a>.
*
@@ -65,11 +66,10 @@ public class LogbackValve extends ValveBase implements Lifecycle, Context,
public final static String DEFAULT_CONFIG_FILE = "conf" + File.separatorChar
+ "logback-access.xml";
-
+
private long birthTime = System.currentTimeMillis();
Object configurationLock = new Object();
-
// Attributes from ContextBase:
private String name;
StatusManager sm = new BasicStatusManager();
@@ -167,8 +167,7 @@ public class LogbackValve extends ValveBase implements Lifecycle, Context,
// TODO better exception handling
aai.appendLoopOnAppenders(accessEvent);
} finally {
- request
- .removeAttribute(AccessConstants.LOGBACK_STATUS_MANAGER_KEY);
+ request.removeAttribute(AccessConstants.LOGBACK_STATUS_MANAGER_KEY);
}
}
@@ -226,6 +225,10 @@ public class LogbackValve extends ValveBase implements Lifecycle, Context,
return (String) this.propertyMap.get(key);
}
+ public Map<String, String> getCopyOfPropertyMap() {
+ return new HashMap<String, String>(this.propertyMap);
+ }
+
public Object getObject(String key) {
return objectMap.get(key);
}
@@ -249,7 +252,7 @@ public class LogbackValve extends ValveBase implements Lifecycle, Context,
public List<Filter<AccessEvent>> getCopyOfAttachedFiltersList() {
return fai.getCopyOfAttachedFiltersList();
}
-
+
public FilterReply getFilterChainDecision(AccessEvent event) {
return fai.getFilterChainDecision(event);
}
@@ -273,7 +276,7 @@ public class LogbackValve extends ValveBase implements Lifecycle, Context,
public Object getConfigurationLock() {
return configurationLock;
}
-
+
// ====== Methods from catalina Lifecycle =====
public void addLifecycleListener(LifecycleListener arg0) {
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql
index 94964fe..536ffbd 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
#
# It is intended for IBM DB2 databases.
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/h2.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/h2.sql
index 94306c8..03ffb89 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/h2.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/h2.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender.
#
# It is intended for H2 databases.
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql
index 671f675..529387c 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql
@@ -1,3 +1,10 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
+
# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender.
#
# It is intended for HSQL databases. It has been tested on HSQL 1.8.07.
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql
index 71a1861..0d74898 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql
@@ -1,3 +1,9 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
-- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
--
-- The event_id column type was recently changed from INT to DECIMAL(40)
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql
index e6ee387..8aed9f4 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql
@@ -1,3 +1,9 @@
+# Logback: the reliable, generic, fast and flexible logging framework.
+# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+#
+# See http://logback.qos.ch/license.html for the applicable licensing
+# conditions.
+
# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender.
#
# It is intended for MySQL databases. It has been tested on MySQL 5.1.37
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql
index 3d239ad..7f3ecb0 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql
@@ -1,7 +1,14 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
+
-- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
--
--- It is intended for Oracle 9i, 10g and 11g databases. Tested on version 9.2, 10g and
--- 11g.
+-- It is intended for Oracle 9i, 10g and 11g databases. Tested on version 9.2,
+-- 10g and 11g.
-- The following lines are useful in cleaning any previously existing tables
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql
index 576f26c..3ccb44a 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql
@@ -1,3 +1,9 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
-- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
--
-- It is intended for PostgreSQL databases.
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/sybaseSqlAnywhere.sql b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/sybaseSqlAnywhere.sql
index 9ad7e70..bbc2624 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/sybaseSqlAnywhere.sql
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/sybaseSqlAnywhere.sql
@@ -1,3 +1,9 @@
+-- Logback: the reliable, generic, fast and flexible logging framework.
+-- Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+--
+-- See http://logback.qos.ch/license.html for the applicable licensing
+-- conditions.
+
-- This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender
-- for Sybase SQLAnywhere. Tested on SQLAnywhere 10.0.1.
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/boolex/JaninoEventEvaluatorTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/boolex/JaninoEventEvaluatorTest.java
index 9763d5d..5b4b8c7 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/boolex/JaninoEventEvaluatorTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/boolex/JaninoEventEvaluatorTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.fail;
import java.io.IOException;
import org.junit.Test;
+import org.slf4j.MDC;
import org.slf4j.MarkerFactory;
import ch.qos.logback.classic.Level;
@@ -34,6 +35,8 @@ import ch.qos.logback.core.boolex.JaninoEventEvaluatorBase;
import ch.qos.logback.core.boolex.Matcher;
import ch.qos.logback.core.filter.EvaluatorFilter;
import ch.qos.logback.core.spi.FilterReply;
+import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.StatusPrinter;
public class JaninoEventEvaluatorTest {
@@ -44,6 +47,8 @@ public class JaninoEventEvaluatorTest {
JaninoEventEvaluator jee = new JaninoEventEvaluator();
+ int diff = RandomUtil.getPositiveInt();
+
public JaninoEventEvaluatorTest() {
jee.setContext(loggerContext);
@@ -99,6 +104,21 @@ public class JaninoEventEvaluatorTest {
assertTrue(jee.evaluate(event));
}
+
+ @Test
+ public void mdcAsString() throws Exception {
+ String k = "key"+diff;
+
+ MDC.put("key"+diff, "value"+diff);
+ jee.setExpression("mdc.get(\""+k+"\").contains(\"alue\")");
+ jee.start();
+ StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
+
+ LoggingEvent event = makeLoggingEvent(null);
+ assertTrue(jee.evaluate(event));
+ MDC.remove(k);
+ }
+
@Test
public void marker() throws Exception {
jee.setExpression("marker.contains(\"BLUE\")");
@@ -109,6 +129,7 @@ public class JaninoEventEvaluatorTest {
assertTrue(jee.evaluate(event));
}
+
@Test
public void withNullMarker_LBCORE_118() throws Exception {
jee.setExpression("marker.contains(\"BLUE\")");
diff --git a/logback-core/src/main/java/ch/qos/logback/core/Context.java b/logback-core/src/main/java/ch/qos/logback/core/Context.java
index 040be88..d348f30 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/Context.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/Context.java
@@ -13,6 +13,8 @@
*/
package ch.qos.logback.core;
+import java.util.Map;
+
import ch.qos.logback.core.spi.PropertyContainer;
import ch.qos.logback.core.status.StatusManager;
@@ -65,6 +67,14 @@ public interface Context extends PropertyContainer {
*/
public void putProperty(String key, String value);
+
+ /**
+ * Get a copy of the property map
+ * @return
+ * @since 0.9.20
+ */
+ public Map<String, String> getCopyOfPropertyMap();
+
/**
* Contexts are named objects.
*
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java b/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
index 681eed3..c66e5b0 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
@@ -29,6 +29,7 @@ import ch.qos.logback.core.joran.action.ParamAction;
import ch.qos.logback.core.joran.action.PropertyAction;
import ch.qos.logback.core.joran.action.StatusListenerAction;
import ch.qos.logback.core.joran.action.TimestampAction;
+import ch.qos.logback.core.joran.conditional.IfAction;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.joran.spi.Interpreter;
import ch.qos.logback.core.joran.spi.Pattern;
@@ -66,6 +67,10 @@ abstract public class JoranConfiguratorBase extends GenericConfigurator {
rs.addRule(new Pattern("configuration/timestamp"),
new TimestampAction());
+ rs.addRule(new Pattern("*/if"),
+ new IfAction());
+
+
// the contextProperty pattern is deprecated. It is undocumented
// and will be dropped in future versions of logback
rs.addRule(new Pattern("configuration/contextProperty"),
@@ -77,6 +82,8 @@ abstract public class JoranConfiguratorBase extends GenericConfigurator {
rs.addRule(new Pattern("configuration/statusListener"),
new StatusListenerAction());
+
+
rs.addRule(new Pattern("configuration/appender"), new AppenderAction());
rs.addRule(new Pattern("configuration/appender/appender-ref"),
new AppenderRefAction());
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
index 696ada9..a19603b 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
@@ -72,7 +72,7 @@ public class Interpreter {
final private InterpretationContext interpretationContext;
final private ArrayList<ImplicitAction> implicitActions;
final private CAI_WithLocatorSupport cai;
- Pattern pattern;
+ public Pattern pattern;
Locator locator;
EventPlayer player;
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java
index 52c36a7..75f64b6 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java
@@ -14,6 +14,7 @@
package ch.qos.logback.core.joran.spi;
import java.util.ArrayList;
+import java.util.List;
/**
* A pattern is used to designate XML elements in a document.
@@ -28,9 +29,14 @@ public class Pattern {
// contains String instances
ArrayList<String> partList = new ArrayList<String>();
+
public Pattern() {
}
+ public Pattern(List<String> list) {
+ partList.addAll(list);
+ }
+
/**
* Build a pattern from a string.
*
@@ -71,6 +77,10 @@ public class Pattern {
// System.out.println(components);
}
+ public List<String> getCopyOfPartList() {
+ return new ArrayList<String>(partList);
+ }
+
public Object clone() {
Pattern p = new Pattern();
p.partList.addAll(this.partList);
@@ -136,10 +146,18 @@ public class Pattern {
break;
}
}
-
return match;
}
+ public boolean isContained(Pattern p) {
+ if(p == null) {
+ return false;
+ }
+ String lStr = this.toString();
+ return lStr.contains(p.toString());
+ }
+
+
/**
* Returns the number of "prefix" components that this pattern has in common
* with the pattern p passed as parameter. By "prefix" components we mean the
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java
index 9a97c21..db5a406 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java
@@ -31,6 +31,8 @@ import ch.qos.logback.core.util.OptionHelper;
*/
public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
+ static String ANY = "*";
+
// key: Pattern instance, value: ArrayList containing actions
HashMap<Pattern, List<Action>> rules = new HashMap<Pattern, List<Action>>();
@@ -86,7 +88,8 @@ public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
} else if ((actionList = tailMatch(currentPattern)) != null) {
return actionList;
} else if ((actionList = prefixMatch(currentPattern)) != null) {
- // System.out.println(currentPattern + " prefixMatches "+actionList);
+ return actionList;
+ } else if ((actionList = middleMatch(currentPattern)) != null) {
return actionList;
} else {
return null;
@@ -99,12 +102,9 @@ public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
for (Pattern p : rules.keySet()) {
- if ((p.size() > 1) && p.get(0).equals("*")) {
+ if ((p.size() > 1) && p.get(0).equals(ANY)) {
int r = currentPattern.getTailMatchLength(p);
-
- // System.out.println("tailMatch " +r);
if (r > max) {
- // System.out.println("New longest tailMatch "+p);
max = r;
longestMatchingPattern = p;
}
@@ -124,11 +124,8 @@ public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
for (Pattern p : rules.keySet()) {
String last = p.peekLast();
- if ("*".equals(last)) {
+ if (ANY.equals(last)) {
int r = currentPattern.getPrefixMatchLength(p);
-
- // System.out.println("r = "+ r + ", p= "+p);
-
// to qualify the match length must equal p's size omitting the '*'
if ((r == p.size() - 1) && (r > max)) {
// System.out.println("New longest prefixMatch "+p);
@@ -139,14 +136,50 @@ public class SimpleRuleStore extends ContextAwareBase implements RuleStore {
}
if (longestMatchingPattern != null) {
- // System.out.println("prefixMatch will return"
- // +rules.get(longestMatchingPattern));
return rules.get(longestMatchingPattern);
} else {
return null;
}
}
+ List middleMatch(Pattern currentPattern) {
+
+ int max = 0;
+ Pattern longestMatchingPattern = null;
+
+ for (Pattern p : rules.keySet()) {
+ String last = p.peekLast();
+ String first = null;
+ if(p.size() > 1) {
+ first = p.get(0);
+ }
+ if (ANY.equals(last) && ANY.equals(first)) {
+ List<String> partList = p.getCopyOfPartList();
+ if(partList.size() > 2) {
+ partList.remove(0);
+ partList.remove(partList.size()-1);
+ }
+
+ int r = 0;
+ Pattern clone = new Pattern(partList);
+ if(currentPattern.isContained(clone)) {
+ r = clone.size();
+ }
+ if (r > max) {
+ max = r;
+ longestMatchingPattern = p;
+ }
+ }
+ }
+
+ if (longestMatchingPattern != null) {
+ return rules.get(longestMatchingPattern);
+ } else {
+ return null;
+ }
+ }
+
+
public String toString() {
final String TAB = " ";
diff --git a/logback-core/src/test/java/ch/qos/logback/core/joran/action/IncludeActionTest.java b/logback-core/src/test/java/ch/qos/logback/core/joran/action/IncludeActionTest.java
index d242e9f..372a00b 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/joran/action/IncludeActionTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/joran/action/IncludeActionTest.java
@@ -52,7 +52,8 @@ public class IncludeActionTest {
Context context = new ContextBase();
TrivialConfigurator tc;
- static final String INCLUSION_DIR_PREFIX = "src/test/input/joran/inclusion/";
+ static final String INCLUSION_DIR_PREFIX = CoreTestConstants.JORAN_INPUT_PREFIX
+ + "inclusion/";
static final String TOP_BY_FILE = INCLUSION_DIR_PREFIX + "topByFile.xml";
@@ -77,7 +78,8 @@ public class IncludeActionTest {
int diff = RandomUtil.getPositiveInt();
- public IncludeActionTest() {
+ @Before
+ public void setUp() throws Exception {
HashMap<Pattern, Action> rulesMap = new HashMap<Pattern, Action>();
rulesMap.put(new Pattern("x"), new NOPAction());
rulesMap.put(new Pattern("x/inc"), new IncAction());
@@ -85,10 +87,6 @@ public class IncludeActionTest {
tc = new TrivialConfigurator(rulesMap);
tc.setContext(context);
- }
-
- @Before
- public void setUp() throws Exception {
IncAction.reset();
}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/util/CoreTestConstants.java b/logback-core/src/test/java/ch/qos/logback/core/util/CoreTestConstants.java
index 29c180c..4b66b9a 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/util/CoreTestConstants.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/util/CoreTestConstants.java
@@ -13,16 +13,16 @@
*/
package ch.qos.logback.core.util;
-
public class CoreTestConstants {
-
+
public static final String TEST_DIR_PREFIX = "src/test/";
+ public static final String JORAN_INPUT_PREFIX = TEST_DIR_PREFIX
+ + "input/joran/";
public static final String OUTPUT_DIR_PREFIX = "target/test-output/";
-
-
+
public static final int SUCCESSFUL_EXIT_CODE = 8;
public static final int FAILURE_EXIT_CODE = 1;
-
+
public static final String BASH_PATH_ON_CYGWIN = "c:/cygwin/bin/bash";
public static final String BASH_PATH_ON_LINUX = "bash";
}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/SimpleConfigurator.java b/logback-examples/src/main/java/chapters/appenders/onJoran/SimpleConfigurator.java
deleted file mode 100644
index b715b60..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/SimpleConfigurator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran;
-
-import java.util.List;
-import java.util.Map;
-
-import ch.qos.logback.core.joran.GenericConfigurator;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.action.ImplicitAction;
-import ch.qos.logback.core.joran.spi.Interpreter;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.joran.spi.RuleStore;
-
-/**
- * A minimal configurator extending GenericConfigurator.
- *
- * @author Ceki Gücü
- *
- */
-public class SimpleConfigurator extends GenericConfigurator {
-
- final Map<Pattern, Action> ruleMap;
- final List<ImplicitAction> iaList;
-
- public SimpleConfigurator(Map<Pattern, Action> ruleMap) {
- this(ruleMap, null);
- }
-
- public SimpleConfigurator(Map<Pattern, Action> ruleMap, List<ImplicitAction> iaList) {
- this.ruleMap = ruleMap;
- this.iaList = iaList;
- }
-
- @Override
- protected void addInstanceRules(RuleStore rs) {
- for (Pattern pattern : ruleMap.keySet()) {
- Action action = ruleMap.get(pattern);
- rs.addRule(pattern, action);
- }
- }
-
- @Override
- protected void addImplicitRules(Interpreter interpreter) {
- if(iaList == null) {
- return;
- }
- for (ImplicitAction ia : iaList) {
- interpreter.addImplicitAction(ia);
- }
- }
-
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/AddAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/AddAction.java
deleted file mode 100644
index 3d6c7e2..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/AddAction.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import java.util.EmptyStackException;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-
-
-/**
- * This action adds the two integers at the top of the stack (they are removed)
- * and pushes the result to the top the stack.
- *
- * @author Ceki Gülcü
- */
-public class AddAction extends Action {
-
- public void begin(InterpretationContext ic, String name, Attributes attributes) {
- int first = fetchInteger(ic);
- int second = fetchInteger(ic);
- // Push the result of the addition for the following actions.
- ic.pushObject(new Integer(first + second));
- }
-
- /**
- * Pop the Integer object at the top of the stack.
- * This code also illustrates usage of Joran's error handling paradigm.
- */
- int fetchInteger(InterpretationContext ic) {
- int result = 0;
-
- try {
- // Pop the object at the top of the interpretation context's stack.
- Object o1 = ic.popObject();
-
- if (o1 instanceof Integer) {
- result = ((Integer) o1).intValue();
- } else {
- String errMsg =
- "Object [" + o1
- + "] currently at the top of the stack is not an integer.";
- ic.addError(errMsg);
- throw new IllegalArgumentException(errMsg);
- }
- } catch (EmptyStackException ese) {
- ic.addError(("Expecting an integer on the execution stack."));
- throw ese;
- }
- return result;
- }
-
- public void end(InterpretationContext ic, String name) {
- // Nothing to do here.
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator1.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator1.java
deleted file mode 100644
index dbe4fbf..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator1.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.ContextBase;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.util.StatusPrinter;
-import chapters.appenders.onJoran.SimpleConfigurator;
-
-/**
- * This examples illustrates collaboration between multiple actions through the
- * common execution context stack.
- *
- * @author Ceki Güulcü
- */
-public class Calculator1 {
-
- public static void main(String[] args) throws Exception {
- Context context = new ContextBase();
-
- Map<Pattern, Action> ruleMap = new HashMap<Pattern, Action>();
-
- // Associate "/computation" pattern with ComputationAction1
- ruleMap.put(new Pattern("/computation"), new ComputationAction1());
-
- // Other associations
- ruleMap.put(new Pattern("/computation/literal"), new LiteralAction());
- ruleMap.put(new Pattern("/computation/add"), new AddAction());
- ruleMap.put(new Pattern("/computation/multiply"), new MultiplyAction());
-
- SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
- // link the configurator with its context
- simpleConfigurator.setContext(context);
-
- simpleConfigurator.doConfigure(args[0]);
- // Print any errors that might have occured.
- StatusPrinter.print(context);
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator2.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator2.java
deleted file mode 100644
index 9b04aad..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator2.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.ContextBase;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.JoranException;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.util.StatusPrinter;
-import chapters.appenders.onJoran.SimpleConfigurator;
-
-
-/**
- * This examples illustrates collaboration between multiple actions through the
- * common execution context stack.
- *
- * It differs from Calculator1 in that it supports arbitrary nesting of
- * computation elements.
- *
- * You can test this application with the sample XML file <em>calculator3.xml</em>.
- *
- * @author Ceki Güulcü
- */
-public class Calculator2 {
- public static void main(String[] args) throws Exception {
- Map<Pattern, Action> ruleMap = new HashMap<Pattern, Action>();
-
-
- // Note the wild card character '*', in the paterns, signifying any level
- // of nesting.
- ruleMap.put(new Pattern("*/computation"), new ComputationAction2());
-
- ruleMap.put(new Pattern("*/computation/literal"), new LiteralAction());
- ruleMap.put(new Pattern("*/computation/add"), new AddAction());
- ruleMap.put(new Pattern("*/computation/multiply"), new MultiplyAction());
-
- Context context = new ContextBase();
- SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
- // link the configurator with its context
- simpleConfigurator.setContext(context);
-
- try {
- simpleConfigurator.doConfigure(args[0]);
- } catch (JoranException e) {
- // Print any errors that might have occured.
- StatusPrinter.print(context);
- }
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction1.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction1.java
deleted file mode 100644
index 7ea7ade..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction1.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-import ch.qos.logback.core.util.OptionHelper;
-
-
-/**
- * ComputationAction1 will print the result of the compuration made by
- * children elements but only if the compuration itself is named, that is if the
- * name attribute of the associated computation element is not null. In other
- * words, anonymous computations will not print their result.
- *
- * @author Ceki Gülcü
- */
-public class ComputationAction1 extends Action {
- public static String NAME_ATR = "name";
-
- String nameStr;
-
- /**
- * Store the value of the name attribute for future use.
- */
- public void begin(InterpretationContext ec, String name, Attributes attributes) {
- nameStr = attributes.getValue(NAME_ATR);
- }
-
- /**
- * Children elements have been processed. The sesults should be an integer
- * placed at the top of the execution stack.
- *
- * This value will be printed on the console but only if the action is
- * named. Anonymous computation will not print their result.
- */
- public void end(InterpretationContext ec, String name) {
- if (OptionHelper.isEmpty(nameStr)) {
- // nothing to do
- } else {
- Integer i = (Integer) ec.peekObject();
- System.out.println(
- "The computation named [" + nameStr + "] resulted in the value " + i);
- }
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction2.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction2.java
deleted file mode 100644
index 749aabe..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction2.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import java.util.Stack;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-import ch.qos.logback.core.util.OptionHelper;
-
-
-/**
- * ComputationAction2 will print the result of the compuration made by
- * children elements but only if the computation itself is named, that is if the
- * name attribute of the associated computation element is not null. In other
- * words, anonymous computations will not print their result.
- *
- * ComputationAction2 differs from ComputationAction1 in its handling of
- * instance variables. ComputationAction1 has a simple <Code>nameStr</code>
- * instance variable. This variable is set when the begin() method is called
- * and then later used within the end() method.
- *
- * This simple approach works properly if the begin() and end()
- * method of a given action are expected to be called in sequence. However,
- * there are situations where the begin() method of the same action instance is
- * invoked multiple times before the matching end() method is invoked.
- *
- * When this happens, the second call to begin() overwrites values set by
- * the first invocation to begin(). The solution is to save parameter values
- * into a separate stack. The well-formedness of XML will guarantee that a value
- * saved by one begin() will be consumed only by the matching end() method.
- *
- * Note that in the vast majority of cases there is no need to resort to a
- * separate stack for each variable. The situation of successive begin()
- * invocations can only occur if:
- *
- * 1) the associated pattern contains a wildcard, i.e. the * character
- *
- * and
- *
- * 2) the associated element tag can contain itself as a child
- *
- * For example, "*/computation" pattern means that computations can contain
- * other computation elements as children.
- *
- * @author Ceki Gülcü
- */
-public class ComputationAction2 extends Action {
- public static String NAME_ATR = "name";
-
- Stack<String> nameStrStack = new Stack<String>();
-
-
- public void begin(InterpretationContext ec, String name, Attributes attributes) {
- String nameStr = attributes.getValue(NAME_ATR);
- // save nameStr value in a special stack. Note that the value is saved
- // even if it is empty or null.
- nameStrStack.push(nameStr);
- }
-
- public void end(InterpretationContext ec, String name) {
- // pop nameStr value from the special stack
- String nameStr = (String) nameStrStack.pop();
-
- if (OptionHelper.isEmpty(nameStr)) {
- // nothing to do
- } else {
- Integer i = (Integer) ec.peekObject();
- System.out.println(
- "The computation named [" + nameStr + "] resulted in the value " + i);
- }
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/LiteralAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/LiteralAction.java
deleted file mode 100644
index 72f4859..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/LiteralAction.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-import ch.qos.logback.core.util.OptionHelper;
-
-/**
- * This action converts the value attribute of the associated element to an
- * integer and pushes the resulting Integer object on top of the execution
- * context stack.
- *
- * <p>It also illustrates usage of Joran's error reporting/handling paradigm.
- *
- * @author Ceki Gülcü
- */
-public class LiteralAction extends Action {
- public static String VALUE_ATR = "value";
-
- public void begin(InterpretationContext ic, String name, Attributes attributes) {
- String valueStr = attributes.getValue(VALUE_ATR);
-
- if (OptionHelper.isEmpty(valueStr)) {
- ic.addError("The literal action requires a value attribute");
- return;
- }
-
- try {
- Integer i = Integer.valueOf(valueStr);
- ic.pushObject(i);
- } catch (NumberFormatException nfe) {
- ic.addError("The value [" + valueStr
- + "] could not be converted to an Integer", nfe);
- throw nfe;
- }
- }
-
- public void end(InterpretationContext ic, String name) {
- // Nothing to do here.
- // In general, the end() method of actions associated with elements
- // having no children do not need to perform any processing in their
- // end() method.
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/MultiplyAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/MultiplyAction.java
deleted file mode 100644
index 89dfcc6..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/MultiplyAction.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.calculator;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-
-import java.util.EmptyStackException;
-
-/**
- *
- * This action multiplies the two integers at the top of the stack (they are
- * removed) and pushes the result on top the stack.
- *
- * @author Ceki Gülcü
- */
-public class MultiplyAction extends Action {
-
- public void begin(InterpretationContext ic, String name, Attributes attributes) {
- int first = fetchInteger(ic);
- int second = fetchInteger(ic);
- ic.pushObject(new Integer(first * second));
- }
-
- /**
- * Pop the Integer object at the top of the stack. This code illustrates usage
- * of Joran's error handling paradigm.
- */
- int fetchInteger(InterpretationContext ic) {
- int result = 0;
-
- try {
- Object o1 = ic.popObject();
-
- if (o1 instanceof Integer) {
- result = ((Integer) o1).intValue();
- } else {
- String errMsg = "Object [" + o1
- + "] currently at the top of the stack is not an integer.";
- ic.addError(errMsg);
- throw new IllegalArgumentException(errMsg);
- }
- } catch (EmptyStackException ese) {
- ic.addError("Expecting an integer on the execution stack.");
- throw ese;
- }
- return result;
- }
-
- public void end(InterpretationContext ic, String name) {
- // Nothing to do here.
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator1.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator1.xml
deleted file mode 100644
index 111db47..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator1.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<computation name="total">
- <literal value="3"/>
-</computation>
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator2.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator2.xml
deleted file mode 100644
index 4a96c62..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator2.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE computation>
-
-<computation name="toto">
- <literal value="7"/>
- <literal value="3"/>
- <add/>
- <literal value="3"/>
- <multiply/>
-</computation>
\ No newline at end of file
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator3.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator3.xml
deleted file mode 100644
index 5c19944..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator3.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-<!-- This file is intended to be executed by Caculator2.
- It is not suited for Calculator1 due to nested computation
- elements.
- -->
-
-<computation name="toto">
- <computation>
- <literal value="7"/>
- <literal value="3"/>
- <add/>
- </computation>
-
- <literal value="3"/>
- <multiply/>
-</computation>
\ No newline at end of file
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/readme.txt b/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/readme.txt
deleted file mode 100644
index a0d9621..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/calculator/readme.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This directory contains the the calculator example. It shows how Actions can
-collaborate in order to accomplish a simple computation.
-
-For further information, please refer to
-
- http://logback.qos.ch/manual/onJoran.html#calculator
-
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorld.java b/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorld.java
deleted file mode 100644
index a23400e..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorld.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.helloWorld;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.ContextBase;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.util.StatusPrinter;
-import chapters.appenders.onJoran.SimpleConfigurator;
-
-/**
- *
- * A hello world example using Joran.
- *
- * @author Ceki Gulcu
- */
-public class HelloWorld {
- public static void main(String[] args) throws Exception {
- Map<Pattern, Action> ruleMap = new HashMap<Pattern, Action>();
-
- // Associate "hello-world" pattern with HelloWorldAction
- ruleMap.put(new Pattern("hello-world"), new HelloWorldAction());
-
- // Joran needs to work within a context.
- Context context = new ContextBase();
- SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
- // link the configurator with its context
- simpleConfigurator.setContext(context);
-
- simpleConfigurator.doConfigure(args[0]);
- StatusPrinter.print(context);
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorldAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorldAction.java
deleted file mode 100644
index 6911df8..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorldAction.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.helloWorld;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-
-/**
- * A trivial action that writes "Hello world" on the console.
- *
- * See the {@link HelloWorld} class for integration with Joran.
- *
- * @author Ceki Gülcü
- */
-public class HelloWorldAction extends Action {
- public void begin(InterpretationContext ec, String name, Attributes attributes) {
- System.out.println("Hello World");
- }
-
- public void end(InterpretationContext ec, String name) {
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/hello.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/hello.xml
deleted file mode 100644
index 7d764cd..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/hello.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<hello-world>
-</hello-world>
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/readme.txt b/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/readme.txt
deleted file mode 100644
index c96bb14..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/readme.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-The example illustrates the minimal plumbing required for using Joran.
-
-For further explanations, please refer to
-
- http://logback.qos.ch/manual/onJoran.html#helloWorld
-
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/NOPAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/NOPAction.java
deleted file mode 100644
index b5018b8..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/NOPAction.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.implicit;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-
-
-/**
- * No operation (NOP) action that does strictly nothing.
- *
- * @author Ceki Gülcü
- */
-public class NOPAction extends Action {
-
- public void begin(InterpretationContext ec, String name, Attributes attributes) {
- }
-
- public void end(InterpretationContext ec, String name) {
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMe.java b/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMe.java
deleted file mode 100644
index 1a190f5..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMe.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.implicit;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.ContextBase;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.action.ImplicitAction;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.util.StatusPrinter;
-import chapters.appenders.onJoran.SimpleConfigurator;
-
-/**
- * This example illustrates the usage of implicit actions.
- *
- * <p>Keep in mind that implicit actions are not associated with any specific
- * pattern. Moreover, they are added directly to a Joran Interpreter instead of
- * a rule store.
- *
- * @author Ceki Güulcü
- */
-public class PrintMe {
-
- public static void main(String[] args) throws Exception {
- Context context = new ContextBase();
-
- Map<Pattern, Action> ruleMap = new HashMap<Pattern, Action>();
-
- // we start with the rule for the top-most (root) element
- ruleMap.put(new Pattern("*/foo"), new NOPAction());
-
- // Add an implicit action.
- List<ImplicitAction> iaList = new ArrayList<ImplicitAction>();
- iaList.add(new PrintMeImplicitAction());
- SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap,
- iaList);
-
- // link the configurator with its context
- simpleConfigurator.setContext(context);
-
- simpleConfigurator.doConfigure(args[0]);
- StatusPrinter.printInCaseOfErrorsOrWarnings(context);
-
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMeImplicitAction.java b/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMeImplicitAction.java
deleted file mode 100644
index 3a473b2..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMeImplicitAction.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.implicit;
-
-import org.xml.sax.Attributes;
-
-import ch.qos.logback.core.joran.action.ImplicitAction;
-import ch.qos.logback.core.joran.spi.InterpretationContext;
-import ch.qos.logback.core.joran.spi.Pattern;
-
-/**
- *
- * A rather trivial implicit action which is applicable if an element has a
- * printme attribute set to true.
- *
- * @author Ceki Gülcü
- */
-public class PrintMeImplicitAction extends ImplicitAction {
-
- public boolean isApplicable(Pattern pattern, Attributes attributes,
- InterpretationContext ec) {
- String printmeStr = attributes.getValue("printme");
-
- return Boolean.valueOf(printmeStr).booleanValue();
- }
-
- public void begin(InterpretationContext ec, String name, Attributes attributes) {
- System.out.println("Element [" + name + "] asked to be printed.");
- }
-
- public void end(InterpretationContext ec, String name) {
- }
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/implicit1.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/implicit1.xml
deleted file mode 100644
index 54fe4d9..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/implicit1.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<foo>
-
- <!-- These elements will print due to the implicit rule -->
- <xyz printme="true">
- <abc printme="true"/>
- </xyz>
-
- <!-- This element has no associated rule and no implicit rule
- applies for it because the printme attribute is not set. -->
- <xyz/>
-
-
-
- <!-- This element will not be printed even if its printme
- attribute is set because implicit rules are invoked only
- if no explicit rule matches the element. The */foo rule
- matches the following element.
- -->
- <foo printme="true"/>
-
-</foo>
\ No newline at end of file
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/readme.txt b/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/readme.txt
deleted file mode 100644
index ad5fc94..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/implicit/readme.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-This directory contains an example illustrating implicit actions.
-
-For further information, please refer to
-
- http://logback.qos.ch/manual/onJoran.html#implicit
-
\ No newline at end of file
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/NewRuleCalculator.java b/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/NewRuleCalculator.java
deleted file mode 100644
index 8fe880f..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/NewRuleCalculator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Logback: the reliable, generic, fast and flexible logging framework.
- * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
- *
- * This program and the accompanying materials are dual-licensed under
- * either the terms of the Eclipse Public License v1.0 as published by
- * the Eclipse Foundation
- *
- * or (per the licensee's choosing)
- *
- * under the terms of the GNU Lesser General Public License version 2.1
- * as published by the Free Software Foundation.
- */
-package chapters.appenders.onJoran.newRule;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import ch.qos.logback.core.Context;
-import ch.qos.logback.core.ContextBase;
-import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.action.NewRuleAction;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.util.StatusPrinter;
-import chapters.appenders.onJoran.SimpleConfigurator;
-import chapters.appenders.onJoran.calculator.ComputationAction1;
-
-/**
- * This example illustrates the usage of NewRuleAction which allows the Joran
- * interpreter to learn new rules on the fly.
- *
- * <p>This example relies heavily on the code from the joran.calculator
- * package.
- *
- * @author Ceki Güulcü
- */
-public class NewRuleCalculator {
- public static void main(String[] args) throws Exception {
-
- Context context = new ContextBase();
-
- Map<Pattern, Action> ruleMap = new HashMap<Pattern, Action>();
-
- // we start with the rule for the top-most (root) element
- ruleMap.put(new Pattern("*/computation"), new ComputationAction1());
-
- // Associate "/new-rule" pattern with NewRuleAction from the
- // org.apache.joran.action package.
- //
- // We will let the XML file to teach the Joran interpreter about new rules
- ruleMap.put(new Pattern("/computation/new-rule"), new NewRuleAction());
-
- SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
- // link the configurator with its context
- simpleConfigurator.setContext(context);
-
- simpleConfigurator.doConfigure(args[0]);
-
- // Print any errors that might have occured.
- StatusPrinter.printInCaseOfErrorsOrWarnings(context);
- }
-
-}
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/new-rule.xml b/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/new-rule.xml
deleted file mode 100644
index ef7b061..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/new-rule.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
- This file is intended to be executed by NewRuleCalculator.
- Note that the rules for adding and multiplying are learned on
- the fly, while parsingthis file.
--->
-
-<computation name="toto">
- <new-rule pattern="*/computation/literal"
- actionClass="chapter10.calculator.LiteralAction"/>
- <new-rule pattern="*/computation/add"
- actionClass="chapter10.calculator.AddAction"/>
- <new-rule pattern="*/computation/multiply"
- actionClass="chapter10.calculator.MultiplyAction"/>
-
- <computation>
- <literal value="7"/>
- <literal value="3"/>
- <add/>
- </computation>
-
- <literal value="3"/>
- <multiply/>
-</computation>
\ No newline at end of file
diff --git a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/readme.txt b/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/readme.txt
deleted file mode 100644
index fb7a5ca..0000000
--- a/logback-examples/src/main/java/chapters/appenders/onJoran/newRule/readme.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-This directory contains an example showing how Joran can
-learn new parsing rules on the fly.
-
-For further documentation please see
-
- http://logback.qos.ch/manual/onJoran.html#newRule
-
diff --git a/logback-site/src/site/pages/manual/filters.html b/logback-site/src/site/pages/manual/filters.html
index 82ca505..01f0dea 100644
--- a/logback-site/src/site/pages/manual/filters.html
+++ b/logback-site/src/site/pages/manual/filters.html
@@ -362,6 +362,15 @@ public class SampleFilter extends Filter>ILoggingEvent> {
<td>A map containing all the MDC values at the time of the
creation of the logging event. A value can be accessed by
using the following expression: <em>mdc.get("myKey")</em>.
+
+ <p>The <code>java.util.Map</code> type is non-parametirezied
+ because Janino does not support generics. It follows that the
+ type returned by <code>mdc.get()</code> is <code>Object</code>
+ and not <code>String</code>. To invoke <code>String</code>
+ methods on the returned value, it must be cast as
+ <code>String</code>. For example,
+ <code>((String) mdc.get("k")).contains("val")</code>.
+ </p>
</td>
</tr>
diff --git a/logback-site/src/site/pages/manual/introduction.html b/logback-site/src/site/pages/manual/introduction.html
index ed1b347..526225a 100644
--- a/logback-site/src/site/pages/manual/introduction.html
+++ b/logback-site/src/site/pages/manual/introduction.html
@@ -138,10 +138,11 @@ public class HelloWorld1 {
<p>Logback can report information about its internal state using a
built-in status system. Important events occuring during logback's
- lifetime can be accessed through a <code>StatusManager</code>. For
- the time being, let us instruct logback to print its internal
- state. This is accomplished by a static method in the
- <code>LoggerStatusPrinter</code> class.
+ lifetime can be accessed through a component called
+ <code>StatusManager</code>. For the time being, let us instruct
+ logback to print its internal state by invoking the static
+ <code>print()</code> method of the <code>StatusPrinter</code>
+ class.
</p>
<em>Example 1.2: Printing Logger Status (<a href="../xref/chapters/introduction/HelloWorld2.html">logback-examples/src/main/java/chapters/introduction/HelloWorld2.java</a>)</em>
diff --git a/logback-site/src/site/pages/news.html b/logback-site/src/site/pages/news.html
index cf7678c..5599a10 100644
--- a/logback-site/src/site/pages/news.html
+++ b/logback-site/src/site/pages/news.html
@@ -35,7 +35,16 @@
<code>LayoutWrappingEncoder</code> not being recognized in config
files.</p>
+ <p>Logback now provides <a
+ href="http://logback.qos.ch/manual/loggingSeparation.html">an
+ answer</a> to the longstanding logging separation problem for
+ static logger references in shared libraries. This fixes <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-166">LBCLASSIC-166</a>
+ and <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-87">LBCLASSIC-87</a>.
+ </p>
+
<!-- ============================================================== -->
-----------------------------------------------------------------------
Summary of changes:
.../java/ch/qos/logback/access/db/dialect/db2.sql | 6 ++
.../qos/logback/access/db/dialect/deleteTables.sql | 3 -
.../ch/qos/logback/access/db/dialect/hsqldb.sql | 6 ++
.../qos/logback/access/db/dialect/msSQLServer.sql | 6 ++
.../ch/qos/logback/access/db/dialect/mysql.sql | 6 ++
.../ch/qos/logback/access/db/dialect/oracle.sql | 6 ++
.../qos/logback/access/db/dialect/postgresql.sql | 6 ++
.../ch/qos/logback/access/sift/SiftAction.java | 10 +-
.../ch/qos/logback/access/tomcat/LogbackValve.java | 17 +++--
.../java/ch/qos/logback/classic/db/dialect/db2.sql | 6 ++
.../java/ch/qos/logback/classic/db/dialect/h2.sql | 6 ++
.../ch/qos/logback/classic/db/dialect/hsqldb.sql | 7 ++
.../ch/qos/logback/classic/db/dialect/mssql.sql | 6 ++
.../ch/qos/logback/classic/db/dialect/mysql.sql | 6 ++
.../ch/qos/logback/classic/db/dialect/oracle.sql | 11 ++-
.../qos/logback/classic/db/dialect/postgresql.sql | 6 ++
.../classic/db/dialect/sybaseSqlAnywhere.sql | 6 ++
.../classic/boolex/JaninoEventEvaluatorTest.java | 21 +++++
.../src/main/java/ch/qos/logback/core/Context.java | 10 +++
.../logback/core/joran/JoranConfiguratorBase.java | 7 ++
.../ch/qos/logback/core/joran/spi/Interpreter.java | 2 +-
.../ch/qos/logback/core/joran/spi/Pattern.java | 20 +++++-
.../logback/core/joran/spi/SimpleRuleStore.java | 55 ++++++++++---
.../core/joran/action/IncludeActionTest.java | 10 +--
.../qos/logback/core/util/CoreTestConstants.java | 10 +-
.../appenders/onJoran/SimpleConfigurator.java | 64 ---------------
.../appenders/onJoran/calculator/AddAction.java | 69 ----------------
.../appenders/onJoran/calculator/Calculator1.java | 55 -------------
.../appenders/onJoran/calculator/Calculator2.java | 64 ---------------
.../onJoran/calculator/ComputationAction1.java | 61 --------------
.../onJoran/calculator/ComputationAction2.java | 86 --------------------
.../onJoran/calculator/LiteralAction.java | 58 -------------
.../onJoran/calculator/MultiplyAction.java | 66 ---------------
.../appenders/onJoran/calculator/calculator1.xml | 3 -
.../appenders/onJoran/calculator/calculator2.xml | 10 ---
.../appenders/onJoran/calculator/calculator3.xml | 16 ----
.../appenders/onJoran/calculator/readme.txt | 7 --
.../appenders/onJoran/helloWorld/HelloWorld.java | 48 -----------
.../onJoran/helloWorld/HelloWorldAction.java | 35 --------
.../appenders/onJoran/helloWorld/hello.xml | 2 -
.../appenders/onJoran/helloWorld/readme.txt | 6 --
.../appenders/onJoran/implicit/NOPAction.java | 34 --------
.../appenders/onJoran/implicit/PrintMe.java | 61 --------------
.../onJoran/implicit/PrintMeImplicitAction.java | 44 ----------
.../appenders/onJoran/implicit/implicit1.xml | 21 -----
.../chapters/appenders/onJoran/implicit/readme.txt | 7 --
.../onJoran/newRule/NewRuleCalculator.java | 63 --------------
.../appenders/onJoran/newRule/new-rule.xml | 23 -----
.../chapters/appenders/onJoran/newRule/readme.txt | 8 --
logback-site/src/site/pages/manual/filters.html | 9 ++
.../src/site/pages/manual/introduction.html | 9 +-
logback-site/src/site/pages/news.html | 11 +++-
52 files changed, 238 insertions(+), 957 deletions(-)
delete mode 100644 logback-access/src/main/java/ch/qos/logback/access/db/dialect/deleteTables.sql
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/SimpleConfigurator.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/AddAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator1.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/Calculator2.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction1.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/ComputationAction2.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/LiteralAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/MultiplyAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator1.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator2.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/calculator3.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/calculator/readme.txt
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorld.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/HelloWorldAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/hello.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/helloWorld/readme.txt
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/implicit/NOPAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMe.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/implicit/PrintMeImplicitAction.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/implicit/implicit1.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/implicit/readme.txt
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/newRule/NewRuleCalculator.java
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/newRule/new-rule.xml
delete mode 100644 logback-examples/src/main/java/chapters/appenders/onJoran/newRule/readme.txt
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0

[JIRA] Closed: (LBCLASSIC-87) LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
by Ceki Gulcu (JIRA) 26 Mar '10
by Ceki Gulcu (JIRA) 26 Mar '10
26 Mar '10
[ http://jira.qos.ch/browse/LBCLASSIC-87?page=com.atlassian.jira.plugin.syste… ]
Ceki Gulcu closed LBCLASSIC-87.
-------------------------------
Fix Version/s: 0.9.19
Resolution: Fixed
This jira entry deals with two different problems both of which are deemed to be solved. Please do not reopen.
> LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
> ---------------------------------------------------------------
>
> Key: LBCLASSIC-87
> URL: http://jira.qos.ch/browse/LBCLASSIC-87
> Project: logback-classic
> Issue Type: Bug
> Components: Other
> Affects Versions: unspecified
> Environment: Operating System: All
> Platform: All
> Reporter: Jens Elkner
> Assignee: Logback dev list
> Fix For: 0.9.19
>
>
> Since LoggerFactory obtains the LoggerContext to use in its static init stage, using a LoggerContextFilter as described in Chapter 8 is completely useless, since the JNDI selector is never consulted again.
> Digging deeper on that issue reveals, that using a ContextJNDISelector (even if it would work) rarely leads to the intended behavior (e.g. webapp related logging), and is probably not thread safe wrt. common practice and intended logging. E.g. in tomcat we have two different cases:
> a) each webapp provides its own slfj4*.jar as well as *logback*.jar
> b) slfj4*.jar as well as *logback*.jar are shared via tomcat/common/lib or
> tomcat/share/lib
> c) a und b mixed
> Well, to get things right, one can say case c) is unsupported ;-).
> In case a) logback has its own playground, so using JNDI doesn't make sense at all, since the webapp/logback has its own playground - doesn't interfere with
> other web apps since loaded via its dedicated classloader.
> However case b) is a little bit more challenging. Here the LoggerFactory and other classes are !shared! between several webapps, since loading is delegated from the dedicated webapp classloader to the shared webapp classloader, which picks up everything in share/lib , common/lib. So right now in 0.9.7, even if one uses JNDISelector a per webapp logging is impossible: The first webapp, which asks for a LoggerFactory always wins! All other webapps, which ask later for a LoggerFactory.getLogger() will get a Logger from the LoggerContext associated with the first webapp, since the context is "cached", i.e. the JNDI selector gets never consulted again.
> Assuming the LoggerFactory problem gets fixed by using e.g.
> public static Logger getLogger(* *) {
> return StaticLoggerBinder.SINGLETON.getLoggerFactory().getLogger(**);
> }
> there is still a problem wrt. common practice aka log* usage pattern and webapp shared classes, which can not be resolved by JNDI: Today most developer use something like:
> public class XY {
> private static [final] Logger log = LoggerFactory.getLogger(XY.class);
> ...
> }
> That implies the same problem, as with the current LoggerFactory bug: The class gets the Logger from the context associated with the first webapp, which needs the shared class. And that's why all other webapps, which later need this class will use the the logger context of the first webapp. So e.g. if webapp A is configured to log to /var/log/a.log and another webapp B is configured to log to /var/log/b.log the loging output of shared classes will always go to /var/log/a.log if webapp used the classes in question first, no matter on which thread aka in which webapp the shared classes are used.
> So even if LoggerFactory gets fixed, JNDI selector is of little use, if one wants to have a webapp dedicated log as soon as shared classes are involved.
> The only way to solve the didcated webapp log problem a can think of, to introduce another level of indirection in the Logger.log* etc. method, which takes care of thread local settings and the settings of its parent threads (e.g. an application may start other threads, which do not inherit the thread local settings from the current thread ...). But this would probably influence the performance of logback in a rather negative way.
> Another idea might be an architecture re-design: sharing Loggers would be no problem because of thread local AppenderContext soft ref, which points to an Appender in the global AppenderStore singleton ...
> RFE: These problems should be reflected chapter 8 of the logback manual to avoid further confusion ...
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0

[JIRA] Reopened: (LBCLASSIC-87) LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
by Ceki Gulcu (JIRA) 26 Mar '10
by Ceki Gulcu (JIRA) 26 Mar '10
26 Mar '10
[ http://jira.qos.ch/browse/LBCLASSIC-87?page=com.atlassian.jira.plugin.syste… ]
Ceki Gulcu reopened LBCLASSIC-87:
---------------------------------
> LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
> ---------------------------------------------------------------
>
> Key: LBCLASSIC-87
> URL: http://jira.qos.ch/browse/LBCLASSIC-87
> Project: logback-classic
> Issue Type: Bug
> Components: Other
> Affects Versions: unspecified
> Environment: Operating System: All
> Platform: All
> Reporter: Jens Elkner
> Assignee: Logback dev list
>
> Since LoggerFactory obtains the LoggerContext to use in its static init stage, using a LoggerContextFilter as described in Chapter 8 is completely useless, since the JNDI selector is never consulted again.
> Digging deeper on that issue reveals, that using a ContextJNDISelector (even if it would work) rarely leads to the intended behavior (e.g. webapp related logging), and is probably not thread safe wrt. common practice and intended logging. E.g. in tomcat we have two different cases:
> a) each webapp provides its own slfj4*.jar as well as *logback*.jar
> b) slfj4*.jar as well as *logback*.jar are shared via tomcat/common/lib or
> tomcat/share/lib
> c) a und b mixed
> Well, to get things right, one can say case c) is unsupported ;-).
> In case a) logback has its own playground, so using JNDI doesn't make sense at all, since the webapp/logback has its own playground - doesn't interfere with
> other web apps since loaded via its dedicated classloader.
> However case b) is a little bit more challenging. Here the LoggerFactory and other classes are !shared! between several webapps, since loading is delegated from the dedicated webapp classloader to the shared webapp classloader, which picks up everything in share/lib , common/lib. So right now in 0.9.7, even if one uses JNDISelector a per webapp logging is impossible: The first webapp, which asks for a LoggerFactory always wins! All other webapps, which ask later for a LoggerFactory.getLogger() will get a Logger from the LoggerContext associated with the first webapp, since the context is "cached", i.e. the JNDI selector gets never consulted again.
> Assuming the LoggerFactory problem gets fixed by using e.g.
> public static Logger getLogger(* *) {
> return StaticLoggerBinder.SINGLETON.getLoggerFactory().getLogger(**);
> }
> there is still a problem wrt. common practice aka log* usage pattern and webapp shared classes, which can not be resolved by JNDI: Today most developer use something like:
> public class XY {
> private static [final] Logger log = LoggerFactory.getLogger(XY.class);
> ...
> }
> That implies the same problem, as with the current LoggerFactory bug: The class gets the Logger from the context associated with the first webapp, which needs the shared class. And that's why all other webapps, which later need this class will use the the logger context of the first webapp. So e.g. if webapp A is configured to log to /var/log/a.log and another webapp B is configured to log to /var/log/b.log the loging output of shared classes will always go to /var/log/a.log if webapp used the classes in question first, no matter on which thread aka in which webapp the shared classes are used.
> So even if LoggerFactory gets fixed, JNDI selector is of little use, if one wants to have a webapp dedicated log as soon as shared classes are involved.
> The only way to solve the didcated webapp log problem a can think of, to introduce another level of indirection in the Logger.log* etc. method, which takes care of thread local settings and the settings of its parent threads (e.g. an application may start other threads, which do not inherit the thread local settings from the current thread ...). But this would probably influence the performance of logback in a rather negative way.
> Another idea might be an architecture re-design: sharing Loggers would be no problem because of thread local AppenderContext soft ref, which points to an Appender in the global AppenderStore singleton ...
> RFE: These problems should be reflected chapter 8 of the logback manual to avoid further confusion ...
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0

[JIRA] Issue Comment Edited: (LBCLASSIC-87) LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
by Ceki Gulcu (JIRA) 26 Mar '10
by Ceki Gulcu (JIRA) 26 Mar '10
26 Mar '10
[ http://jira.qos.ch/browse/LBCLASSIC-87?page=com.atlassian.jira.plugin.syste… ]
Ceki Gulcu edited comment on LBCLASSIC-87 at 3/26/10 5:19 PM:
--------------------------------------------------------------
As of version 0.9.19, logback provides a way to address the logging separation problem for static logger references in shared libraries. Please see http://logback.qos.ch/manual/loggingSeparation.html#tamingStaticRefs
was (Author: noreply.ceki(a)qos.ch)
As of version 0.9.19, logback provides a way to address the logging separation problem for static logger references in shared libraries. Please see http://logback.qos.ch/manual/loggingSeparation.html
> LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
> ---------------------------------------------------------------
>
> Key: LBCLASSIC-87
> URL: http://jira.qos.ch/browse/LBCLASSIC-87
> Project: logback-classic
> Issue Type: Bug
> Components: Other
> Affects Versions: unspecified
> Environment: Operating System: All
> Platform: All
> Reporter: Jens Elkner
> Assignee: Logback dev list
>
> Since LoggerFactory obtains the LoggerContext to use in its static init stage, using a LoggerContextFilter as described in Chapter 8 is completely useless, since the JNDI selector is never consulted again.
> Digging deeper on that issue reveals, that using a ContextJNDISelector (even if it would work) rarely leads to the intended behavior (e.g. webapp related logging), and is probably not thread safe wrt. common practice and intended logging. E.g. in tomcat we have two different cases:
> a) each webapp provides its own slfj4*.jar as well as *logback*.jar
> b) slfj4*.jar as well as *logback*.jar are shared via tomcat/common/lib or
> tomcat/share/lib
> c) a und b mixed
> Well, to get things right, one can say case c) is unsupported ;-).
> In case a) logback has its own playground, so using JNDI doesn't make sense at all, since the webapp/logback has its own playground - doesn't interfere with
> other web apps since loaded via its dedicated classloader.
> However case b) is a little bit more challenging. Here the LoggerFactory and other classes are !shared! between several webapps, since loading is delegated from the dedicated webapp classloader to the shared webapp classloader, which picks up everything in share/lib , common/lib. So right now in 0.9.7, even if one uses JNDISelector a per webapp logging is impossible: The first webapp, which asks for a LoggerFactory always wins! All other webapps, which ask later for a LoggerFactory.getLogger() will get a Logger from the LoggerContext associated with the first webapp, since the context is "cached", i.e. the JNDI selector gets never consulted again.
> Assuming the LoggerFactory problem gets fixed by using e.g.
> public static Logger getLogger(* *) {
> return StaticLoggerBinder.SINGLETON.getLoggerFactory().getLogger(**);
> }
> there is still a problem wrt. common practice aka log* usage pattern and webapp shared classes, which can not be resolved by JNDI: Today most developer use something like:
> public class XY {
> private static [final] Logger log = LoggerFactory.getLogger(XY.class);
> ...
> }
> That implies the same problem, as with the current LoggerFactory bug: The class gets the Logger from the context associated with the first webapp, which needs the shared class. And that's why all other webapps, which later need this class will use the the logger context of the first webapp. So e.g. if webapp A is configured to log to /var/log/a.log and another webapp B is configured to log to /var/log/b.log the loging output of shared classes will always go to /var/log/a.log if webapp used the classes in question first, no matter on which thread aka in which webapp the shared classes are used.
> So even if LoggerFactory gets fixed, JNDI selector is of little use, if one wants to have a webapp dedicated log as soon as shared classes are involved.
> The only way to solve the didcated webapp log problem a can think of, to introduce another level of indirection in the Logger.log* etc. method, which takes care of thread local settings and the settings of its parent threads (e.g. an application may start other threads, which do not inherit the thread local settings from the current thread ...). But this would probably influence the performance of logback in a rather negative way.
> Another idea might be an architecture re-design: sharing Loggers would be no problem because of thread local AppenderContext soft ref, which points to an Appender in the global AppenderStore singleton ...
> RFE: These problems should be reflected chapter 8 of the logback manual to avoid further confusion ...
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0

[JIRA] Created: (LBCLASSIC-166) Static logger references in shared classes doesn't work with JNDIContextSelector
by Gabriele Contini (JIRA) 26 Mar '10
by Gabriele Contini (JIRA) 26 Mar '10
26 Mar '10
Static logger references in shared classes doesn't work with JNDIContextSelector
--------------------------------------------------------------------------------
Key: LBCLASSIC-166
URL: http://jira.qos.ch/browse/LBCLASSIC-166
Project: logback-classic
Issue Type: New Feature
Components: Other
Affects Versions: 0.917
Reporter: Gabriele Contini
Assignee: Logback dev list
The issue was already described in: LBCLASSIC-87 by Lars Ködderitzsch
{quote}
As Jens already pointed out the most common pattern to logging (even in common libaries as Jakarta Commons, Spring whatsoever) is using a static logger, eg.
public class XY {
private static [final] Logger log = LoggerFactory.getLogger(XY.class);
...
}
If such libraries are shared (either by being in tomcats shared libs, or by being directly in the ear) by multiple webapps, the logger context wins in which the original loading of the logging class (aka XY, see above) happens.
To make an example.
An ear contains two webapplications A and B, both have different logger context CtxA and CtxB.
A library (say Spring for instance) is place in the ear and both webapps reference the library through their MANIFEST.MF.
On application startup webapp A gets initialized first, during initialisation the classes of the shared libary (Spring) are loaded, therefor static loggers initialized with the context CtxA.
Now webapp B gets initialized, classes of the shared libary are already loaded by the EARClassloader, the loggers continue to use CtxA.
At runtime regardless of wich logger context will be set by context selectors of the webapps, all logging done by the shared classes will always go to CtxA.
One can argue that common libaries should not use static loggers, but always obtain loggers freshly from the LoggerFactory. But that is a pipe dream, because the de-facto pattern in obtaining and using a logger is through a static field as depicted above.
To achieve true per-webapp logging, already initialized loggers need to be able to switch logger contexts, for instance through TreadLocal or other mechanisms.
{quote}
And was closed with:
{quote}
If you need static references problem to be dealt with, then please file a *new* jira issue.
{quote}
I want to separate hibernate logs in my j2ee application (under jboss). Hibernate is included in server libs, and it uses static loggers:
{code}
public class XY {
private static [final] Logger log = LoggerFactory.getLogger(XY.class);
...
}
{code}
I also want to use separate configuration files for each j2ee application (so sifting appender is not enough), thus i'm using the JndiContextSelector.
Logback is unable to switch context once hibernate is initialized, and the logger separation doesn't work for static loggers in shared libraries.
---
I also tried to do my own ContextSelector in order to have a Logger that perform a jndi lookup when it's needed but:
* ''LoggerContext'' has a method ''getLogger(String)'' that is final. I can't override LoggerContext and return my own instance of Logger.
* In my opinion the ''contextSelector.getLoggerContext()'' could return a ''ILoggerFactory'' (there is no need it returns a full ''LoggerContext''
Best regards.
Gabriele Contini
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
2
4

[JIRA] Commented: (LBCLASSIC-87) LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
by Ceki Gulcu (JIRA) 26 Mar '10
by Ceki Gulcu (JIRA) 26 Mar '10
26 Mar '10
[ http://jira.qos.ch/browse/LBCLASSIC-87?page=com.atlassian.jira.plugin.syste… ]
Ceki Gulcu commented on LBCLASSIC-87:
-------------------------------------
As of version 0.9.19, logback provides a way to address the logging separation problem for static logger references in shared libraries. Please see http://logback.qos.ch/manual/loggingSeparation.html
> LoggerContextFilter is useless (org.slf4j.Loggerfactory bug ++)
> ---------------------------------------------------------------
>
> Key: LBCLASSIC-87
> URL: http://jira.qos.ch/browse/LBCLASSIC-87
> Project: logback-classic
> Issue Type: Bug
> Components: Other
> Affects Versions: unspecified
> Environment: Operating System: All
> Platform: All
> Reporter: Jens Elkner
> Assignee: Logback dev list
>
> Since LoggerFactory obtains the LoggerContext to use in its static init stage, using a LoggerContextFilter as described in Chapter 8 is completely useless, since the JNDI selector is never consulted again.
> Digging deeper on that issue reveals, that using a ContextJNDISelector (even if it would work) rarely leads to the intended behavior (e.g. webapp related logging), and is probably not thread safe wrt. common practice and intended logging. E.g. in tomcat we have two different cases:
> a) each webapp provides its own slfj4*.jar as well as *logback*.jar
> b) slfj4*.jar as well as *logback*.jar are shared via tomcat/common/lib or
> tomcat/share/lib
> c) a und b mixed
> Well, to get things right, one can say case c) is unsupported ;-).
> In case a) logback has its own playground, so using JNDI doesn't make sense at all, since the webapp/logback has its own playground - doesn't interfere with
> other web apps since loaded via its dedicated classloader.
> However case b) is a little bit more challenging. Here the LoggerFactory and other classes are !shared! between several webapps, since loading is delegated from the dedicated webapp classloader to the shared webapp classloader, which picks up everything in share/lib , common/lib. So right now in 0.9.7, even if one uses JNDISelector a per webapp logging is impossible: The first webapp, which asks for a LoggerFactory always wins! All other webapps, which ask later for a LoggerFactory.getLogger() will get a Logger from the LoggerContext associated with the first webapp, since the context is "cached", i.e. the JNDI selector gets never consulted again.
> Assuming the LoggerFactory problem gets fixed by using e.g.
> public static Logger getLogger(* *) {
> return StaticLoggerBinder.SINGLETON.getLoggerFactory().getLogger(**);
> }
> there is still a problem wrt. common practice aka log* usage pattern and webapp shared classes, which can not be resolved by JNDI: Today most developer use something like:
> public class XY {
> private static [final] Logger log = LoggerFactory.getLogger(XY.class);
> ...
> }
> That implies the same problem, as with the current LoggerFactory bug: The class gets the Logger from the context associated with the first webapp, which needs the shared class. And that's why all other webapps, which later need this class will use the the logger context of the first webapp. So e.g. if webapp A is configured to log to /var/log/a.log and another webapp B is configured to log to /var/log/b.log the loging output of shared classes will always go to /var/log/a.log if webapp used the classes in question first, no matter on which thread aka in which webapp the shared classes are used.
> So even if LoggerFactory gets fixed, JNDI selector is of little use, if one wants to have a webapp dedicated log as soon as shared classes are involved.
> The only way to solve the didcated webapp log problem a can think of, to introduce another level of indirection in the Logger.log* etc. method, which takes care of thread local settings and the settings of its parent threads (e.g. an application may start other threads, which do not inherit the thread local settings from the current thread ...). But this would probably influence the performance of logback in a rather negative way.
> Another idea might be an architecture re-design: sharing Loggers would be no problem because of thread local AppenderContext soft ref, which points to an Appender in the global AppenderStore singleton ...
> RFE: These problems should be reflected chapter 8 of the logback manual to avoid further confusion ...
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0

[JIRA] Created: (LBCLASSIC-200) explain how logging separation can work for shared classes using JNDIBasedContextDiscriminator
by Ceki Gulcu (JIRA) 26 Mar '10
by Ceki Gulcu (JIRA) 26 Mar '10
26 Mar '10
explain how logging separation can work for shared classes using JNDIBasedContextDiscriminator
----------------------------------------------------------------------------------------------
Key: LBCLASSIC-200
URL: http://jira.qos.ch/browse/LBCLASSIC-200
Project: logback-classic
Issue Type: Task
Components: Other
Affects Versions: 0.9.19
Reporter: Ceki Gulcu
Assignee: Logback dev list
http://www.qos.ch/pipermail/logback-user/2010-March/001457.html
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
2

[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. release_0.9.19-4-g39d30d0
by git-noreply@pixie.qos.ch 26 Mar '10
by git-noreply@pixie.qos.ch 26 Mar '10
26 Mar '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 39d30d0f0028dfd75177a298231d086b4dddbb73 (commit)
from ce0e6110ca1550aaa14c571db5f17de9accb6214 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=39d30d0f0028dfd75177a298…
http://github.com/ceki/logback/commit/39d30d0f0028dfd75177a298231d086b4dddb…
commit 39d30d0f0028dfd75177a298231d086b4dddbb73
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Fri Mar 26 16:59:57 2010 +0100
- fixed http://jira.qos.ch/browse/LBCLASSIC-200
- minor edits
diff --git a/logback-site/src/site/pages/manual/loggingSeparation.html b/logback-site/src/site/pages/manual/loggingSeparation.html
index cd69a95..04f7054 100644
--- a/logback-site/src/site/pages/manual/loggingSeparation.html
+++ b/logback-site/src/site/pages/manual/loggingSeparation.html
@@ -230,7 +230,7 @@
<p>When the web-application is recycled or shutdown, we strongly
recommend that the incumbent <code>LoggerContext</code> be closed
- so that it can be properly gargabe collected. Logback ships with a
+ so that it can be properly garbage collected. Logback ships with a
<code>ServletContextListener</code> called <a
href="../xref/ch/qos/logback/classic/selector/servlet/ContextDetachingSCL.html"><code>ContextDetachingSCL</code></a>,
designed specifically for detaching the
@@ -312,11 +312,12 @@
by virtue of <code>ContextJNDISelector</code>.
</p>
- <p>If a class, say Mustafar, belongs to a library shared by both
- kenobi and yoda, as long as Mustafar has non static loggers, each
- invocation of <code>LoggerFactory.getLogger()</code> will return a
- logger belonging to a logger context associated with the
- calling/current application. But if Mustafar has a static logger
+ <p>If a class, say <code>Mustafar</code>, belongs to a library
+ shared by both <em>kenobi</em> and <em>yoda</em>, as long as
+ <code>Mustafar</code> has non static loggers, each invocation of
+ <code>LoggerFactory.getLogger()</code> will return a logger
+ belonging to a logger context associated with the calling/current
+ application. But if <code>Mustafar</code> has a static logger
reference, then its logger will be attach to logger context of the
application that calls it first. Thus,
<code>ContextJNDISelector</code> does not provide logging
@@ -324,22 +325,21 @@
references. This corner case has eluded a solution for eons.</p>
-
<p>The only way to solve this issue transparently and perfectly
would be to introduce another level of indirection inside loggers
so that each logger-shell somehow delegated work to an inner
logger attached to the appropriate context. This approach would be
quite difficult to implement and would incur a significant
- computational overhead. It is not an approach logback developpers
- plan to pursue.
+ computational overhead. It is not an approach we plan to pursue.
</p>
-
- <p>One could trivially solve the "shared class static logger"
- problem by moving the shared classes inside the web-apps (unshare
- them). If unsharing is not possible, then let <a
+ <p>It goes without saying that one could trivially solve the
+ "shared class static logger" problem by moving the shared classes
+ inside the web-apps (unshare them). If unsharing is not possible,
+ then we can solicit the magical powers of <a
href="appenders.html#SiftingAppender"><code>SiftingAppender</code></a>
- separate logging using JNDI data as separation criteria.
+ in order to separate logging using JNDI data as separation
+ criteria.
</p>
<p>Logback ships with a discriminator called <a
@@ -363,7 +363,7 @@
<appender name="FILE-${contextName}" class="ch.qos.logback.core.FileAppender">
<file><b>${contextName}.log</b></file>
<encoder>
- <pattern>%-50(%level %logger{35}) %contextName - %msg%n</pattern>
+ <pattern>%-50(%level %logger{35}) cn=%contextName - %msg%n</pattern>
</encoder>
</appender>
</sift>
@@ -375,28 +375,111 @@
</configuration></pre>
- <p>If kenobi and yoda are web-applications, then the above
- configuration will output yoda's logs output to <em>yoda.log</em>
- and kenobi's logs to <em>kenobi.log</em>, this even logs generated
- by static logger refences located in shared classes.</p>
+ <p>If kenobi and yoda are web-applications, then the above
+ configuration will output yoda's logs output to <em>yoda.log</em>
+ and kenobi's logs to <em>kenobi.log</em>, this even logs generated
+ by static logger references located in shared classes.</p>
+
+ <p>You can try out the technique just described with the help of the
+ <a
+ href="http://github.com/ceki/logback-starwars">logback-starwars</a>
+ project.
+ </p>
+
+
+ <p>The above approach solves the logging separation problem but is
+ rather complex. It requires the proper installation of
+ <code>ContextJNDISelector</code> and mandates that appenders be
+ wrapped by <code>SiftingAppender</code> which is a non-trivial beast
+ in itself.
+ </p>
+
+ <p>Note that each logging context can be configured using the same
+ file or alternatively different files. The choice is up to
+ you. Instructing all contexts to use the same configuration file
+ is simpler as only one file has to be maintained. Maintaining a
+ distinct configuration file for each application is harder to
+ maintain but allows for more flexibility.</p>
+
+ <p>So are we done yet? Can we declare victory and go home? Well, not
+ quite.</p>
+
+ <p>Let's assume the web-application <code>yoda</code> is initialized
+ before <code>kenobi</code>. To initialize <code>yoda</code>, visit
+ <code>http://localhost:port/yoda/servlet</code> which will invoke
+ the <code>YodaServlet</code>. This servlet just says hello and logs
+ message before calling the <code>foo</code> method in
+ <code>Mustafar</code> which not-surprisingly logs a simple message
+ and returns.
+ </p>
+
+ <p>After <code>YodaServlet</code> is called, the contents of
+ <em>yoda.log</em> file should contain</p>
+
+ <pre class="source">DEBUG ch.qos.starwars.yoda.YodaServlet cn=yoda - in doGet()
+DEBUG ch.qos.starwars.shared.Mustafar cn=yoda - in foo()</pre>
+
+ <p>Note how both log entries are associated with the "yoda" context
+ name. At this stage and until the server stops, the
+ <code>ch.qos.starwars.shared.Mustafar</code> logger is attached to
+ the 'yoda' context and will remain so until the server is stopped.
+ </p>
+
+ <p>Visiting <code>http://localhost:port/kenobi/servlet</code> will
+ output the following in <em>kenobi.log</em>.</p>
+
+ <pre class="source">DEBUG c.qos.starwars.kenobi.KenobiServlet <b>cn=kenobi</b> - in doGet()
+DEBUG ch.qos.starwars.shared.Mustafar <b>cn=yoda</b> - in foo()</pre>
+
+ <p>Note that even if the
+ <code>ch.qos.starwars.shared.Mustafar</code> logger outputs to
+ <em>kenobi.log</em> it is still attached to 'yoda'. Thus, we have
+ two distinct logging contexts logging to the same file, in this
+ case <em>kenobi.log</em>. Each of these contexts reference
+ <code>FileAppender</code> instances, nested within distinct
+ <code>SiftingAppender</code> instances, logging to the same
+ file. Although logging separation seems to function according to
+ our wishes, FileAppender instances cannot safely write to the same
+ file unless they enable <span class="option">prudent</span>
+ mode. Otherwise, the target file will be corrupted.</p>
+
+ <p>Here is the configuration file enabling prudent mode:</p>
+
+ <pre class="prettyprint source"><configuration>
+
+ <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+
+ <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+ <discriminator class="ch.qos.logback.classic.sift.JNDIBasedContextDiscriminator">
+ <defaultValue>unknown</defaultValue>
+ </discriminator>
+ <sift>
+ <appender name="FILE-${contextName}" class="ch.qos.logback.core.FileAppender">
+ <file>${contextName}.log</file>
+ <b><prudent>true</prudent></b>
+ <encoder>
+ <pattern>%-50(%level %logger{35}) cn=%contextName - %msg%n</pattern>
+ </encoder>
+ </appender>
+ </sift>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="SIFT" />
+ </root>
+</configuration></pre>
- <p>The above approach solves the logging separation problem but is
- rather complex. It requires the proper installation of
- <code>ContextJNDISelector</code> and mandates that appenders be
- wrapped by <code>SiftingAppender</code> which is a non-trivial beast
- in itself.
- </p>
- <p>Note that each logging context can be confiured using the same
- file or alternatively different files. The choice is up to
- you. Instruicting all contexts to use the same configuiration file
- is simpler as only one file has to be maintained. Maintaining a
- distinct configuration file for each application is harder to
- maintain but allows for more flexibility.</p>
+ <p>If you were able to keep up with the discussion thus far and
+ have actually tried the logback-starwars examples, then you must be
+ truly obsessed with logging. You should seek <a
+ href="http://www.qos.ch/shop/products/professionalSupport">professional
+ help</a>.</p>
- <p>So are we done yet? Well, not quite.</p>
- <script src="../templates/footer.js"
- type="text/javascript"></script> </div>
- </body> </html>
+ <script src="../templates/footer.js"
+ type="text/javascript"></script> </div>
+
+ </body>
+</html>
diff --git a/logback-site/src/site/pages/reasonsToSwitch.html b/logback-site/src/site/pages/reasonsToSwitch.html
index 4889038..877887d 100644
--- a/logback-site/src/site/pages/reasonsToSwitch.html
+++ b/logback-site/src/site/pages/reasonsToSwitch.html
@@ -196,10 +196,10 @@ java.lang.Exception: 99 is invalid
</p>
- <h3><a name="maxHistory" href="#maxHistory">Automatic erasure of
+ <h3><a name="maxHistory" href="#maxHistory">Automatic removal of
old log archives</a></h3>
- <p>By setting the <span class="option">MaxHistory</span> property
+ <p>By setting the <span class="option">maxHistory</span> property
of <a
href="manual/appenders.html#TimeBasedRollingPolicy">TimeBasedRollingPolicy</a>
or <a
@@ -207,11 +207,10 @@ java.lang.Exception: 99 is invalid
you can control the maximum number of archived files. If your
rolling policy calls for monthly rollover and you wish to keep 1
year's worth of logs, simply set the <span
- class="option">MaxHistory</span> property to 12. Archived log
+ class="option">maxHistory</span> property to 12. Archived log
files older than 12 months will be automatically removed.
</p>
-
<h3><a name="inSummary" href="#inSummary">In summary</a></h3>
<p>We have listed a number of reasons for preferring logback over
-----------------------------------------------------------------------
Summary of changes:
.../src/site/pages/manual/loggingSeparation.html | 153 +++++++++++++++-----
logback-site/src/site/pages/reasonsToSwitch.html | 7 +-
2 files changed, 121 insertions(+), 39 deletions(-)
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0