You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2016/09/14 19:21:28 UTC

[3/3] logging-log4j2 git commit: [LOG4J2-1578] RoutingAppender can be configured with scripts.

[LOG4J2-1578] RoutingAppender can be configured with scripts. 

Add a shared ConcurrentMap for the RoutingAppender's start script and
the Routes route choosing script.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/42c89a28
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/42c89a28
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/42c89a28

Branch: refs/heads/master
Commit: 42c89a28e52caa2ace22722456441d3ad5ee1ba8
Parents: c7c7217
Author: Gary Gregory <gg...@apache.org>
Authored: Wed Sep 14 12:21:18 2016 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Wed Sep 14 12:21:18 2016 -0700

----------------------------------------------------------------------
 .../log4j/core/appender/routing/Routes.java     | 27 +++++++---
 .../core/appender/routing/RoutingAppender.java  | 20 +++++---
 .../core/config/AbstractConfiguration.java      |  2 +-
 .../log4j/core/script/ScriptManager.java        | 54 +++++++++++++++-----
 .../routing/DefaultRouteScriptAppenderTest.java | 32 +++++++++---
 .../log4j-routing-script-staticvars-groovy.xml  | 47 +++++++++++++++++
 ...g4j-routing-script-staticvars-javascript.xml | 47 +++++++++++++++++
 7 files changed, 196 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
index 33fccd7..060fc9b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
@@ -18,7 +18,7 @@ package org.apache.logging.log4j.core.appender.routing;
 
 import java.util.Objects;
 
-import javax.script.SimpleBindings;
+import javax.script.Bindings;
 
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.script.AbstractScript;
+import org.apache.logging.log4j.core.script.ScriptManager;
 import org.apache.logging.log4j.status.StatusLogger;
 
 /**
@@ -61,6 +62,7 @@ public final class Routes {
             if (patternScript != null && pattern != null) {
                 LOGGER.warn("In a Routes element, you must configure either a Script element or a pattern attribute.");
             }
+            Bindings bindings = null;
             if (patternScript != null) {
                 if (configuration == null) {
                     LOGGER.error("No Configuration defined for Routes; required for Script");
@@ -134,12 +136,14 @@ public final class Routes {
         return new Builder();
     }
     
+    private Bindings bindings;
+    
     private final Configuration configuration;
     
     private final String pattern;
-    
-    private final AbstractScript patternScript;
 
+    private final AbstractScript patternScript;
+    
     // TODO Why not make this a Map or add a Map.
     private final Route[] routes;
 
@@ -150,16 +154,21 @@ public final class Routes {
         this.routes = routes;
     }
 
+    public Bindings getBindings() {
+        return bindings;
+    }
+
     /**
      * Returns the pattern.
      * @return the pattern.
      */
     public String getPattern() {
         if (patternScript != null) {
-            final SimpleBindings bindings = new SimpleBindings();
-            bindings.put("configuration", configuration);
-            bindings.put("statusLogger", LOGGER);
-            final Object object = configuration.getScriptManager().execute(patternScript.getName(), bindings);
+            final ScriptManager scriptManager = configuration.getScriptManager();
+            if (bindings == null) {
+                bindings = scriptManager.createBindings(patternScript);
+            }
+            final Object object = scriptManager.execute(patternScript.getName(), bindings);
             return Objects.toString(object, null);
         }
         return pattern;
@@ -190,6 +199,10 @@ public final class Routes {
         return routes;
     }
 
+    public void setBindings(final Bindings bindings) {
+        this.bindings = bindings;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("{");

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
index 78fddbc..d2749b7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
@@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 
+import javax.script.Bindings;
 import javax.script.SimpleBindings;
 
 import org.apache.logging.log4j.core.Appender;
@@ -38,6 +39,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.script.AbstractScript;
+import org.apache.logging.log4j.core.script.ScriptManager;
 import org.apache.logging.log4j.core.util.Booleans;
 
 /**
@@ -137,6 +139,7 @@ public final class RoutingAppender extends AbstractAppender {
     }
 
     private static final String DEFAULT_KEY = "ROUTING_APPENDER_DEFAULT";
+    
     private final Routes routes;
     private Route defaultRoute;
     private final Configuration configuration;
@@ -144,7 +147,8 @@ public final class RoutingAppender extends AbstractAppender {
     private final RewritePolicy rewritePolicy;
     private final PurgePolicy purgePolicy;
     private final AbstractScript defaultRouteScript;
-
+    private Bindings bindings;
+    
     private RoutingAppender(final String name, final Filter filter, final boolean ignoreExceptions, final Routes routes,
             final RewritePolicy rewritePolicy, final Configuration configuration, final PurgePolicy purgePolicy,
             AbstractScript defaultRouteScript) {
@@ -176,11 +180,11 @@ public final class RoutingAppender extends AbstractAppender {
             if (configuration == null) {
                 error("No Configuration defined for RoutingAppender; required for Script element.");
             } else {
-                configuration.getScriptManager().addScript(defaultRouteScript);
-                final SimpleBindings bindings = new SimpleBindings();
-                bindings.put("configuration", configuration);
-                bindings.put("statusLogger", LOGGER);
-                final Object object = configuration.getScriptManager().execute(defaultRouteScript.getName(), bindings);
+                final ScriptManager scriptManager = configuration.getScriptManager();
+                scriptManager.addScript(defaultRouteScript);
+                bindings = scriptManager.createBindings(defaultRouteScript);
+                routes.setBindings(bindings);
+                final Object object = scriptManager.execute(defaultRouteScript.getName(), bindings);
                 final Route route = routes.getRoute(Objects.toString(object, null));
                 if (route != null) {
                     defaultRoute = route;
@@ -361,4 +365,8 @@ public final class RoutingAppender extends AbstractAppender {
     public Configuration getConfiguration() {
         return configuration;
     }
+
+    public Bindings getBindings() {
+        return bindings;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index c6373c1..6933cdd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -205,7 +205,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
     public void initialize() {
         LOGGER.debug("Initializing configuration {}", this);
         subst.setConfiguration(this);
-        scriptManager = new ScriptManager(watchManager);
+        scriptManager = new ScriptManager(this, watchManager);
         pluginManager.collectPlugins(pluginPackages);
         final PluginManager levelPlugins = new PluginManager(Level.CATEGORY);
         levelPlugins.collectPlugins(pluginPackages);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
index fce16d3..23556b4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
@@ -32,8 +32,10 @@ import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+import javax.script.SimpleBindings;
 
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.util.FileWatcher;
 import org.apache.logging.log4j.core.util.WatchManager;
 import org.apache.logging.log4j.status.StatusLogger;
@@ -42,16 +44,33 @@ import org.apache.logging.log4j.status.StatusLogger;
  * Manages the scripts use by the Configuration.
  */
 public class ScriptManager implements FileWatcher, Serializable {
+    
+    private abstract class AbstractScriptRunner implements ScriptRunner {
+        private final ConcurrentMap<Object, Object> scriptStaticVariables = new ConcurrentHashMap<>();
+        
+        @Override
+        public Bindings createBindings() {
+            final SimpleBindings bindings = new SimpleBindings();
+            bindings.put("configuration", configuration);
+            bindings.put("statusLogger", logger);
+            bindings.put("staticVariables", scriptStaticVariables);
+            return bindings;
+        }
+
+    }
+
     private static final long serialVersionUID = -2534169384971965196L;
     private static final String KEY_THREADING = "THREADING";
     private static final Logger logger = StatusLogger.getLogger();
     
+    private final Configuration configuration;
     private final ScriptEngineManager manager = new ScriptEngineManager();
-    private final ConcurrentMap<String, ScriptRunner> scripts = new ConcurrentHashMap<>();
+    private final ConcurrentMap<String, ScriptRunner> scriptRunners = new ConcurrentHashMap<>();
     private final String languages;
     private final WatchManager watchManager;
 
-    public ScriptManager(final WatchManager watchManager) {
+    public ScriptManager(final Configuration configuration, final WatchManager watchManager) {
+        this.configuration = configuration;
         this.watchManager = watchManager;
         final List<ScriptEngineFactory> factories = manager.getEngineFactories();
         if (logger.isDebugEnabled()) {
@@ -101,9 +120,9 @@ public class ScriptManager implements FileWatcher, Serializable {
             return;
         }
         if (engine.getFactory().getParameter(KEY_THREADING) == null) {
-            scripts.put(script.getName(), new ThreadLocalScriptRunner(script));
+            scriptRunners.put(script.getName(), new ThreadLocalScriptRunner(script));
         } else {
-            scripts.put(script.getName(), new MainScriptRunner(engine, script));
+            scriptRunners.put(script.getName(), new MainScriptRunner(engine, script));
         }
 
         if (script instanceof ScriptFile) {
@@ -115,14 +134,18 @@ public class ScriptManager implements FileWatcher, Serializable {
         }
     }
 
+    public Bindings createBindings(AbstractScript script) {
+        return getScriptRunner(script).createBindings();
+    }
+
     public AbstractScript getScript(final String name) {
-        final ScriptRunner runner = scripts.get(name);
+        final ScriptRunner runner = scriptRunners.get(name);
         return runner != null ? runner.getScript() : null;
     }
 
     @Override
     public void fileModified(final File file) {
-        final ScriptRunner runner = scripts.get(file.toString());
+        final ScriptRunner runner = scriptRunners.get(file.toString());
         if (runner == null) {
             logger.info("{} is not a running script");
             return;
@@ -130,15 +153,15 @@ public class ScriptManager implements FileWatcher, Serializable {
         final ScriptEngine engine = runner.getScriptEngine();
         final AbstractScript script = runner.getScript();
         if (engine.getFactory().getParameter(KEY_THREADING) == null) {
-            scripts.put(script.getName(), new ThreadLocalScriptRunner(script));
+            scriptRunners.put(script.getName(), new ThreadLocalScriptRunner(script));
         } else {
-            scripts.put(script.getName(), new MainScriptRunner(engine, script));
+            scriptRunners.put(script.getName(), new MainScriptRunner(engine, script));
         }
 
     }
 
     public Object execute(final String name, final Bindings bindings) {
-        final ScriptRunner scriptRunner = scripts.get(name);
+        final ScriptRunner scriptRunner = scriptRunners.get(name);
         if (scriptRunner == null) {
             logger.warn("No script named {} could be found");
             return null;
@@ -153,6 +176,8 @@ public class ScriptManager implements FileWatcher, Serializable {
 
     private interface ScriptRunner {
 
+        Bindings createBindings();
+        
         Object execute(Bindings bindings);
 
         AbstractScript getScript();
@@ -160,7 +185,7 @@ public class ScriptManager implements FileWatcher, Serializable {
         ScriptEngine getScriptEngine();
     }
 
-    private class MainScriptRunner implements ScriptRunner {
+    private class MainScriptRunner extends AbstractScriptRunner {
         private final AbstractScript script;
         private final CompiledScript compiledScript;
         private final ScriptEngine scriptEngine;
@@ -219,7 +244,7 @@ public class ScriptManager implements FileWatcher, Serializable {
         }
     }
 
-    private class ThreadLocalScriptRunner implements ScriptRunner {
+    private class ThreadLocalScriptRunner extends AbstractScriptRunner {
         private final AbstractScript script;
 
         private final ThreadLocal<MainScriptRunner> runners = new ThreadLocal<MainScriptRunner>() {
@@ -242,10 +267,13 @@ public class ScriptManager implements FileWatcher, Serializable {
         public AbstractScript getScript() {
             return script;
         }
-
-        @Override
+       @Override
         public ScriptEngine getScriptEngine() {
             return runners.get().getScriptEngine();
         }
     }
+
+    public ScriptRunner getScriptRunner(AbstractScript script) {
+        return scriptRunners.get(script.getName());
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
index 3165eb6..f3f5ad3 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertTrue;
 import java.util.List;
 import java.util.Map;
 
+import javax.script.Bindings;
+
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.config.AppenderControl;
@@ -39,18 +41,34 @@ import org.junit.runners.Parameterized;
 @RunWith(Parameterized.class)
 public class DefaultRouteScriptAppenderTest {
 
-    @Parameterized.Parameters(name = "{0}")
-    public static String[] getParameters() {
-        return new String[] { 
-                "log4j-routing-default-route-script-groovy.xml",
-                "log4j-routing-default-route-script-javascript.xml" };
+    @Parameterized.Parameters(name = "{0} {1}")
+    public static Object[][] getParameters() {
+        // @formatter:off
+        return new Object[][] { 
+                { "log4j-routing-default-route-script-groovy.xml", false },
+                { "log4j-routing-default-route-script-javascript.xml", false },
+                { "log4j-routing-script-staticvars-javascript.xml", true },
+                { "log4j-routing-script-staticvars-groovy.xml", true },
+        };
+        // @formatter:on
     }
 
     @Rule
     public final LoggerContextRule loggerContextRule;
 
-    public DefaultRouteScriptAppenderTest(final String configLocation) {
+    private final boolean expectBindingEntries;
+
+    public DefaultRouteScriptAppenderTest(final String configLocation, final boolean expectBindingEntries) {
         this.loggerContextRule = new LoggerContextRule(configLocation);
+        this.expectBindingEntries = expectBindingEntries;
+    }
+
+    private void checkStaticVars() {
+        final RoutingAppender routingAppender = getRoutingAppender();
+        final Bindings bindings = routingAppender.getBindings();
+        if (expectBindingEntries) {
+            Assert.assertEquals("TestValue2", ((Map<?, ?>) bindings.get("staticVariables")).get("TestKey"));
+        }
     }
 
     private ListAppender getListAppender() {
@@ -118,10 +136,12 @@ public class DefaultRouteScriptAppenderTest {
     @Test
     public void testRoutingPresence1() {
         logAndCheck();
+        checkStaticVars();
     }
 
     @Test
     public void testRoutingPresence2() {
         logAndCheck();
+        checkStaticVars();
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/test/resources/log4j-routing-script-staticvars-groovy.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-routing-script-staticvars-groovy.xml b/log4j-core/src/test/resources/log4j-routing-script-staticvars-groovy.xml
new file mode 100644
index 0000000..1c16152
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-routing-script-staticvars-groovy.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="WARN" name="RoutingTest">
+  <Appenders>
+    <Routing name="Routing">
+      <Script name="RoutingInit" language="groovy"><![CDATA[
+        staticVariables.put("TestKey", "TestValue1");
+        return "OSNameFoo".contains("Foo") ? "Service2": "Service1";]]>
+      </Script>
+      <Routes>
+        <Script name="RoutesInit" language="groovy"><![CDATA[
+          if (staticVariables.containsKey("TestKey")) {
+            staticVariables.put("TestKey", "TestValue2");
+          }
+          return "OSNameFoo".contains("Foo") ? "Service2": "Service1";]]>
+        </Script>
+        <Route key="Service1">
+          <List name="List1" />
+        </Route>
+        <Route key="Service2">
+          <List name="List2" />
+        </Route>
+      </Routes>
+    </Routing>
+  </Appenders>
+  <Loggers>
+    <Root level="error">
+      <AppenderRef ref="Routing" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/42c89a28/log4j-core/src/test/resources/log4j-routing-script-staticvars-javascript.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-routing-script-staticvars-javascript.xml b/log4j-core/src/test/resources/log4j-routing-script-staticvars-javascript.xml
new file mode 100644
index 0000000..d3493ad
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-routing-script-staticvars-javascript.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="WARN" name="RoutingTest">
+  <Appenders>
+    <Routing name="Routing">
+      <Script name="RoutingInit" language="JavaScript"><![CDATA[
+        staticVariables.put("TestKey", "TestValue1");
+        "OSNameFoo".search("Foo") > -1 ? "Service2" : "Service1";]]>
+      </Script>
+      <Routes>
+        <Script name="RoutesInit" language="JavaScript"><![CDATA[
+          if (staticVariables.containsKey("TestKey")) {
+            staticVariables.put("TestKey", "TestValue2");
+          }
+          "OSNameFoo".search("Foo") > -1 ? "Service2" : "Service1";]]>
+        </Script>
+        <Route key="Service1">
+          <List name="List1" />
+        </Route>
+        <Route key="Service2">
+          <List name="List2" />
+        </Route>
+      </Routes>
+    </Routing>
+  </Appenders>
+  <Loggers>
+    <Root level="error">
+      <AppenderRef ref="Routing" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file