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