Ralph: Thank you for the guidance on this topic. I'll tackle the documentation update tonight.
WRT Lookups, that's YAGNI for me ATM. If you have a solution path on that, I can take a look. I am wondering in general about the performance difference from an app POV between a plain appender and one appender nested in a RoutingAppender. I am also wondering about any concurrency issue passing a LogEvent to a Script. Can a LogEvent be skipped when multiple threads use the same RoutingAppender? Gary On Wed, Sep 14, 2016 at 12:50 PM, Ralph Goers <ralph.go...@dslextreme.com> wrote: > Sounds good. > > When documenting that you should make it clear that the Map is shared so > that every thread is seeing the same Map. Users need to be aware that they > cannot put things in the map and expect it to only be available for that > single event. > > The last, and probably trickiest part, is going to be making it so > variables in the Map can be accessed via a Lookup. To be honest, I haven’t > really figured out how to do that. > > Ralph > > On Sep 14, 2016, at 12:34 PM, Gary Gregory <garydgreg...@gmail.com> wrote: > > The RoutingAppender Scripts now share a Bindings instance which contains a > ConcurrentMap keyed under "staticVariables". The Bindings instance is > tracked as a RoutingAppender and Routes ivar. > > I created an abstract superclass for (private) ScriptRunner > implementations which holds on to the ConcurrentMap. The map can act as a > set of static/global variables for that script and can be shared through a > Bindings instance. The private ScriptRunner has new method > ScriptManager.ScriptRunner.createBindings(). Right now there is no script > specific data added to the Bindings, but there could be in the future. > > I'll add LogEvent support next... > > Gary > > On Wed, Sep 14, 2016 at 6:42 AM, Ralph Goers <ralph.go...@dslextreme.com> > wrote: > >> OK - It wasn’t in there when I looked last night. >> >> A couple other things. A ConcurrentMap should be created and passed to >> the init script and the routing script so that the init script can pass >> variables to the routing script. Also, the routing script really needs to >> be passed the logEvent so it can route based on data within it. >> >> Ralph >> >> On Sep 13, 2016, at 10:49 PM, Gary Gregory <garydgreg...@gmail.com> >> wrote: >> >> On Tue, Sep 13, 2016 at 10:33 PM, Ralph Goers <ralph.go...@dslextreme.com >> > wrote: >> >>> Gary, >>> >>> RoutingAppender calls routes.getPattern(). Wouldn’t it make sense for >>> the Routes class to execute the script in the call to getPattern and return >>> the result if there is a script? >>> >> >> That's what Routes.getPattern() does (see this very commit thread): >> >> @@ -90,12 +155,26 @@ public final class Routes { >> * @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); >> + return Objects.toString(object, null); >> + } >> return pattern; >> } >> >> Gary >> >> >>> >>> Ralph >>> >>> > On Sep 13, 2016, at 10:00 PM, ggreg...@apache.org wrote: >>> > >>> > Repository: logging-log4j2 >>> > Updated Branches: >>> > refs/heads/master 3846e2a87 -> e0f29d9ad >>> > >>> > >>> > [LOG4J2-1578] RoutingAppender can be configured with scripts. Add >>> Script >>> > in a Routes element. >>> > >>> > Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo >>> > Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j >>> 2/commit/e0f29d9a >>> > Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/ >>> tree/e0f29d9a >>> > Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/ >>> diff/e0f29d9a >>> > >>> > Branch: refs/heads/master >>> > Commit: e0f29d9ad73aa4579cdc2d71ae5e8c01dd4f9f9c >>> > Parents: 3846e2a >>> > Author: Gary Gregory <ggreg...@apache.org> >>> > Authored: Tue Sep 13 21:59:59 2016 -0700 >>> > Committer: Gary Gregory <ggreg...@apache.org> >>> > Committed: Tue Sep 13 21:59:59 2016 -0700 >>> > >>> > ---------------------------------------------------------------------- >>> > .../log4j/core/appender/routing/Routes.java | 121 >>> ++++++++++++----- >>> > .../core/appender/routing/RoutingAppender.java | 19 ++- >>> > .../routing/RoutesScriptAppenderTest.java | 130 >>> +++++++++++++++++++ >>> > .../log4j-routing-routes-script-groovy.xml | 43 ++++++ >>> > .../log4j-routing-routes-script-javascript.xml | 40 ++++++ >>> > src/site/xdoc/manual/appenders.xml | 27 +++- >>> > 6 files changed, 340 insertions(+), 40 deletions(-) >>> > ---------------------------------------------------------------------- >>> > >>> > >>> > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob >>> /e0f29d9a/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/app >>> ender/routing/Routes.java >>> > index c95b64a..33fccd7 100644 >>> > --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/routing/Routes.java >>> > +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/routing/Routes.java >>> > @@ -18,11 +18,17 @@ package org.apache.logging.log4j.core. >>> appender.routing; >>> > >>> > import java.util.Objects; >>> > >>> > +import javax.script.SimpleBindings; >>> > + >>> > import org.apache.logging.log4j.Logger; >>> > +import org.apache.logging.log4j.core.config.Configuration; >>> > import org.apache.logging.log4j.core.config.plugins.Plugin; >>> > import org.apache.logging.log4j.core.config.plugins.PluginAttribute; >>> > import org.apache.logging.log4j.core.config.plugins.PluginBuilderFa >>> ctory; >>> > +import org.apache.logging.log4j.core.config.plugins.PluginConfigura >>> tion; >>> > import org.apache.logging.log4j.core.config.plugins.PluginElement; >>> > +import org.apache.logging.log4j.core.config.plugins.validation.cons >>> traints.Required; >>> > +import org.apache.logging.log4j.core.script.AbstractScript; >>> > import org.apache.logging.log4j.status.StatusLogger; >>> > >>> > /** >>> > @@ -33,54 +39,113 @@ public final class Routes { >>> > >>> > public static class Builder implements >>> org.apache.logging.log4j.core.util.Builder<Routes> { >>> > >>> > + @PluginConfiguration >>> > + private Configuration configuration; >>> > + >>> > @PluginAttribute("pattern") >>> > private String pattern; >>> > >>> > - @PluginElement("Routes") >>> > + @PluginElement("Script") >>> > + private AbstractScript patternScript; >>> > + >>> > + @PluginElement("Routes") >>> > + @Required >>> > private Route[] routes; >>> > >>> > @Override >>> > public Routes build() { >>> > if (routes == null || routes.length == 0) { >>> > - LOGGER.error("No routes configured"); >>> > + LOGGER.error("No Routes configured."); >>> > return null; >>> > } >>> > - return new Routes(pattern, routes); >>> > + if (patternScript != null && pattern != null) { >>> > + LOGGER.warn("In a Routes element, you must configure >>> either a Script element or a pattern attribute."); >>> > + } >>> > + if (patternScript != null) { >>> > + if (configuration == null) { >>> > + LOGGER.error("No Configuration defined for >>> Routes; required for Script"); >>> > + } else { >>> > + configuration.getScriptManager >>> ().addScript(patternScript); >>> > + } >>> > + } >>> > + return new Routes(configuration, patternScript, pattern, >>> routes); >>> > + } >>> > + >>> > + public Configuration getConfiguration() { >>> > + return configuration; >>> > } >>> > >>> > public String getPattern() { >>> > return pattern; >>> > } >>> > >>> > + public AbstractScript getPatternScript() { >>> > + return patternScript; >>> > + } >>> > + >>> > public Route[] getRoutes() { >>> > return routes; >>> > } >>> > >>> > - public Builder withPattern(@SuppressWarnings("hiding") >>> String pattern) { >>> > + public Builder withConfiguration(@SuppressWarnings("hiding") >>> final Configuration configuration) { >>> > + this.configuration = configuration; >>> > + return this; >>> > + } >>> > + >>> > + public Builder withPattern(@SuppressWarnings("hiding") final >>> String pattern) { >>> > this.pattern = pattern; >>> > return this; >>> > } >>> > >>> > - public Builder withRoutes(@SuppressWarnings("hiding") >>> Route[] routes) { >>> > + public Builder withPatternScript(@SuppressWarnings("hiding") >>> final AbstractScript patternScript) { >>> > + this.patternScript = patternScript; >>> > + return this; >>> > + } >>> > + >>> > + public Builder withRoutes(@SuppressWarnings("hiding") final >>> Route[] routes) { >>> > this.routes = routes; >>> > return this; >>> > } >>> > >>> > } >>> > >>> > + private static final Logger LOGGER = StatusLogger.getLogger(); >>> > + >>> > + /** >>> > + * Creates the Routes. >>> > + * @param pattern The pattern. >>> > + * @param routes An array of Route elements. >>> > + * @return The Routes container. >>> > + * @deprecated since 2.7; use {@link #newBuilder()}. >>> > + */ >>> > + @Deprecated >>> > + public static Routes createRoutes( >>> > + final String pattern, >>> > + final Route... routes) { >>> > + if (routes == null || routes.length == 0) { >>> > + LOGGER.error("No routes configured"); >>> > + return null; >>> > + } >>> > + return new Routes(null, null, pattern, routes); >>> > + } >>> > + >>> > @PluginBuilderFactory >>> > public static Builder newBuilder() { >>> > return new Builder(); >>> > } >>> > - >>> > - private static final Logger LOGGER = StatusLogger.getLogger(); >>> > - >>> > + >>> > + private final Configuration configuration; >>> > + >>> > private final String pattern; >>> > >>> > + private final AbstractScript patternScript; >>> > + >>> > // TODO Why not make this a Map or add a Map. >>> > private final Route[] routes; >>> > >>> > - private Routes(final String pattern, final Route... routes) { >>> > + private Routes(final Configuration configuration, final >>> AbstractScript patternScript, final String pattern, final Route... routes) { >>> > + this.configuration = configuration; >>> > + this.patternScript = patternScript; >>> > this.pattern = pattern; >>> > this.routes = routes; >>> > } >>> > @@ -90,12 +155,26 @@ public final class Routes { >>> > * @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); >>> > + return Objects.toString(object, null); >>> > + } >>> > return pattern; >>> > } >>> > >>> > - public Route getRoute(String key) { >>> > - for (int i = 0; i < routes.length; i++) { >>> > - final Route route = routes[i]; >>> > + /** >>> > + * Gets the optional script that decides which route to pick. >>> > + * @return the optional script that decides which route to pick. >>> May be null. >>> > + */ >>> > + public AbstractScript getPatternScript() { >>> > + return patternScript; >>> > + } >>> > + >>> > + public Route getRoute(final String key) { >>> > + for (final Route route : routes) { >>> > if (Objects.equals(route.getKey(), key)) { >>> > return route; >>> > } >>> > @@ -127,22 +206,4 @@ public final class Routes { >>> > >>> > } >>> > >>> > - /** >>> > - * Creates the Routes. >>> > - * @param pattern The pattern. >>> > - * @param routes An array of Route elements. >>> > - * @return The Routes container. >>> > - * @deprecated since 2.7; use {@link #newBuilder()}. >>> > - */ >>> > - @Deprecated >>> > - public static Routes createRoutes( >>> > - final String pattern, >>> > - final Route... routes) { >>> > - if (routes == null || routes.length == 0) { >>> > - LOGGER.error("No routes configured"); >>> > - return null; >>> > - } >>> > - return new Routes(pattern, routes); >>> > - } >>> > - >>> > } >>> > >>> > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob >>> /e0f29d9a/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/app >>> ender/routing/RoutingAppender.java >>> > index 4471333..78fddbc 100644 >>> > --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/routing/RoutingAppender.java >>> > +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/app >>> ender/routing/RoutingAppender.java >>> > @@ -72,15 +72,16 @@ public final class RoutingAppender extends >>> AbstractAppender { >>> > >>> > @Override >>> > public RoutingAppender build() { >>> > - if (getName() == null) { >>> > - LOGGER.error("No name defined for RoutingAppender"); >>> > + final String name = getName(); >>> > + if (name == null) { >>> > + LOGGER.error("No name defined for this >>> RoutingAppender"); >>> > return null; >>> > } >>> > if (routes == null) { >>> > - LOGGER.error("No routes defined for RoutingAppender"); >>> > + LOGGER.error("No routes defined for RoutingAppender >>> {}", name); >>> > return null; >>> > } >>> > - return new RoutingAppender(getName(), getFilter(), >>> isIgnoreExceptions(), routes, rewritePolicy, >>> > + return new RoutingAppender(name, getFilter(), >>> isIgnoreExceptions(), routes, rewritePolicy, >>> > configuration, purgePolicy, defaultRouteScript); >>> > } >>> > >>> > @@ -173,7 +174,7 @@ public final class RoutingAppender extends >>> AbstractAppender { >>> > public void start() { >>> > if (defaultRouteScript != null) { >>> > if (configuration == null) { >>> > - error("No Configuration defined for RoutingAppender; >>> required for DefaultRouteScript"); >>> > + error("No Configuration defined for RoutingAppender; >>> required for Script element."); >>> > } else { >>> > configuration.getScriptManage >>> r().addScript(defaultRouteScript); >>> > final SimpleBindings bindings = new SimpleBindings(); >>> > @@ -352,4 +353,12 @@ public final class RoutingAppender extends >>> AbstractAppender { >>> > public RewritePolicy getRewritePolicy() { >>> > return rewritePolicy; >>> > } >>> > + >>> > + public Routes getRoutes() { >>> > + return routes; >>> > + } >>> > + >>> > + public Configuration getConfiguration() { >>> > + return configuration; >>> > + } >>> > } >>> > >>> > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob >>> /e0f29d9a/log4j-core/src/test/java/org/apache/logging/log4j/ >>> core/appender/routing/RoutesScriptAppenderTest.java >>> > ---------------------------------------------------------------------- >>> > diff --git a/log4j-core/src/test/java/org >>> /apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java >>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/app >>> ender/routing/RoutesScriptAppenderTest.java >>> > new file mode 100644 >>> > index 0000000..7d90f6b >>> > --- /dev/null >>> > +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/app >>> ender/routing/RoutesScriptAppenderTest.java >>> > @@ -0,0 +1,130 @@ >>> > +/* >>> > + * 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. >>> > + */ >>> > +package org.apache.logging.log4j.core.appender.routing; >>> > + >>> > +import static org.junit.Assert.assertNotNull; >>> > +import static org.junit.Assert.assertTrue; >>> > + >>> > +import java.util.List; >>> > +import java.util.Map; >>> > + >>> > +import org.apache.logging.log4j.core.LogEvent; >>> > +import org.apache.logging.log4j.core.Logger; >>> > +import org.apache.logging.log4j.core.config.AppenderControl; >>> > +import org.apache.logging.log4j.junit.LoggerContextRule; >>> > +import org.apache.logging.log4j.test.appender.ListAppender; >>> > +import org.junit.Assert; >>> > +import org.junit.Rule; >>> > +import org.junit.Test; >>> > +import org.junit.runner.RunWith; >>> > +import org.junit.runners.Parameterized; >>> > + >>> > +/** >>> > + * >>> > + */ >>> > +@RunWith(Parameterized.class) >>> > +public class RoutesScriptAppenderTest { >>> > + >>> > + @Parameterized.Parameters(name = "{0}") >>> > + public static String[] getParameters() { >>> > + return new String[] { >>> > + "log4j-routing-routes-script-groovy.xml", >>> > + "log4j-routing-routes-script-javascript.xml" }; >>> > + } >>> > + >>> > + @Rule >>> > + public final LoggerContextRule loggerContextRule; >>> > + >>> > + public RoutesScriptAppenderTest(final String configLocation) { >>> > + this.loggerContextRule = new LoggerContextRule(configLocati >>> on); >>> > + } >>> > + >>> > + private ListAppender getListAppender() { >>> > + final String key = "Service2"; >>> > + final RoutingAppender routingAppender = getRoutingAppender(); >>> > + Assert.assertTrue(routingAppender.isStarted()); >>> > + final Map<String, AppenderControl> appenders = >>> routingAppender.getAppenders(); >>> > + final AppenderControl appenderControl = appenders.get(key); >>> > + assertNotNull("No appender control generated for '" + key + >>> "'; appenders = " + appenders, appenderControl); >>> > + final ListAppender listAppender = (ListAppender) >>> appenderControl.getAppender(); >>> > + return listAppender; >>> > + } >>> > + >>> > + private RoutingAppender getRoutingAppender() { >>> > + return loggerContextRule.getRequiredAppender("Routing", >>> RoutingAppender.class); >>> > + } >>> > + >>> > + private void logAndCheck() { >>> > + final Logger logger = loggerContextRule.getLogger(Ro >>> utesScriptAppenderTest.class); >>> > + logger.error("Hello"); >>> > + final ListAppender listAppender = getListAppender(); >>> > + final List<LogEvent> list = listAppender.getEvents(); >>> > + assertNotNull("No events generated", list); >>> > + assertTrue("Incorrect number of events. Expected 1, got " + >>> list.size(), list.size() == 1); >>> > + logger.error("World"); >>> > + assertTrue("Incorrect number of events. Expected 2, got " + >>> list.size(), list.size() == 2); >>> > + } >>> > + >>> > + @Test(expected = AssertionError.class) >>> > + public void testAppenderAbsence() { >>> > + loggerContextRule.getListAppender("List1"); >>> > + } >>> > + >>> > + @Test >>> > + public void testListAppenderPresence() { >>> > + // No appender until an event is routed, even thought we >>> initialized the default route on startup. >>> > + Assert.assertNull("No appender control generated", >>> getRoutingAppender().getAppenders().get("Service2")); >>> > + } >>> > + >>> > + @Test >>> > + public void testNoPurgePolicy() { >>> > + // No PurgePolicy in this test >>> > + Assert.assertNull("Unexpected PurgePolicy", >>> getRoutingAppender().getPurgePolicy()); >>> > + } >>> > + >>> > + @Test >>> > + public void testNoRewritePolicy() { >>> > + // No RewritePolicy in this test >>> > + Assert.assertNull("Unexpected RewritePolicy", >>> getRoutingAppender().getRewritePolicy()); >>> > + } >>> > + >>> > + @Test >>> > + public void testRoutingAppenderRoutes() { >>> > + final RoutingAppender routingAppender = getRoutingAppender(); >>> > + Assert.assertNull(routingAppender.getDefaultRouteScript()); >>> > + Assert.assertNull(routingAppender.getDefaultRoute()); >>> > + final Routes routes = routingAppender.getRoutes(); >>> > + Assert.assertNotNull(routes); >>> > + Assert.assertNotNull(routes.getPatternScript()); >>> > + Assert.assertEquals("Service2", routes.getPattern()); >>> > + } >>> > + >>> > + @Test >>> > + public void testRoutingAppenderPresence() { >>> > + getRoutingAppender(); >>> > + } >>> > + >>> > + @Test >>> > + public void testRoutingPresence1() { >>> > + logAndCheck(); >>> > + } >>> > + >>> > + @Test >>> > + public void testRoutingPresence2() { >>> > + logAndCheck(); >>> > + } >>> > +} >>> > >>> > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob >>> /e0f29d9a/log4j-core/src/test/resources/log4j-routing-routes >>> -script-groovy.xml >>> > ---------------------------------------------------------------------- >>> > diff --git a/log4j-core/src/test/resource >>> s/log4j-routing-routes-script-groovy.xml b/log4j-core/src/test/resource >>> s/log4j-routing-routes-script-groovy.xml >>> > new file mode 100644 >>> > index 0000000..83121ea >>> > --- /dev/null >>> > +++ b/log4j-core/src/test/resources/log4j-routing-routes-script- >>> groovy.xml >>> > @@ -0,0 +1,43 @@ >>> > +<?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"> >>> > + <Routes> >>> > + <Script name="RoutingInit" language="groovy"><![CDATA[ >>> > + if ("OSNameFoo".contains("Foo")) { >>> > + return "Service2"; >>> > + } >>> > + return "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 >>> /e0f29d9a/log4j-core/src/test/resources/log4j-routing-routes >>> -script-javascript.xml >>> > ---------------------------------------------------------------------- >>> > diff --git a/log4j-core/src/test/resource >>> s/log4j-routing-routes-script-javascript.xml >>> b/log4j-core/src/test/resources/log4j-routing-routes-script- >>> javascript.xml >>> > new file mode 100644 >>> > index 0000000..e672aea >>> > --- /dev/null >>> > +++ b/log4j-core/src/test/resources/log4j-routing-routes-script- >>> javascript.xml >>> > @@ -0,0 +1,40 @@ >>> > +<?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"> >>> > + <Routes> >>> > + <Script name="RoutingInit" language="JavaScript"><![CDATA[ >>> > + "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 >>> > >>> > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob >>> /e0f29d9a/src/site/xdoc/manual/appenders.xml >>> > ---------------------------------------------------------------------- >>> > diff --git a/src/site/xdoc/manual/appenders.xml >>> b/src/site/xdoc/manual/appenders.xml >>> > index 2d3d361..a87d9b7 100644 >>> > --- a/src/site/xdoc/manual/appenders.xml >>> > +++ b/src/site/xdoc/manual/appenders.xml >>> > @@ -3279,7 +3279,11 @@ public class JpaLogEntity extends >>> AbstractLogEventWrapperEntity { >>> > Appender may be an appender previously configured and may >>> be referenced by its name or the >>> > Appender can be dynamically created as needed. The >>> RoutingAppender should be configured after any >>> > Appenders it references to allow it to shut down properly. >>> > - </p> >>> > + </p> >>> > + <p> >>> > + You can also configure a RoutingAppender with scripts: >>> you can run a script when the appender starts >>> > + and when a route is chosen for an log event. >>> > + </p> >>> > <table> >>> > <caption align="top">RoutingAppender Parameters</caption> >>> > <tr> >>> > @@ -3288,7 +3292,7 @@ public class JpaLogEntity extends >>> AbstractLogEventWrapperEntity { >>> > <th>Description</th> >>> > </tr> >>> > <tr> >>> > - <td>filter</td> >>> > + <td>Filter</td> >>> > <td>Filter</td> >>> > <td>A Filter to determine if the event should be handled >>> by this Appender. More than one Filter >>> > may be used by using a CompositeFilter.</td> >>> > @@ -3299,16 +3303,22 @@ public class JpaLogEntity extends >>> AbstractLogEventWrapperEntity { >>> > <td>The name of the Appender.</td> >>> > </tr> >>> > <tr> >>> > - <td>rewritePolicy</td> >>> > + <td>RewritePolicy</td> >>> > <td>RewritePolicy</td> >>> > <td>The RewritePolicy that will manipulate the >>> LogEvent.</td> >>> > </tr> >>> > <tr> >>> > - <td>routes</td> >>> > + <td>Routes</td> >>> > <td>Routes</td> >>> > <td>Contains one or more Route declarations to identify >>> the criteria for choosing Appenders.</td> >>> > </tr> >>> > <tr> >>> > + <td>Script</td> >>> > + <td>Script</td> >>> > + <td>This Script runs when Log4j starts the >>> RoutingAppender and returns a String Route key to determine >>> > + the default Route.</td> >>> > + </tr> >>> > + <tr> >>> > <td>ignoreExceptions</td> >>> > <td>boolean</td> >>> > <td>The default is <code>true</code>, causing exceptions >>> encountered while appending events to be >>> > @@ -3319,13 +3329,20 @@ public class JpaLogEntity extends >>> AbstractLogEventWrapperEntity { >>> > </table> >>> > <h4>Routes</h4> >>> > <p> >>> > - The Routes element accepts a single, required attribute >>> named "pattern". The pattern is evaluated >>> > + The Routes element accepts a single attribute named >>> "pattern". The pattern is evaluated >>> > against all the registered Lookups and the result is >>> used to select a Route. Each Route may be >>> > configured with a key. If the key matches the result of >>> evaluating the pattern then that Route >>> > will be selected. If no key is specified on a Route then >>> that Route is the default. Only one Route >>> > can be configured as the default. >>> > </p> >>> > <p> >>> > + The Routes element may contain a Script child element. >>> If specified, the Script is run for each >>> > + log event and returns the String Route key to use. >>> > + </p> >>> > + <p> >>> > + You must specify either the pattern attribute or the >>> Script element, but not both. >>> > + </p> >>> > + <p> >>> > Each Route must reference an Appender. If the Route >>> contains a ref attribute then the >>> > Route will reference an Appender that was defined in the >>> configuration. If the Route contains an >>> > Appender definition then an Appender will be created >>> within the context of the RoutingAppender and >>> > >>> > >>> >>> >>> >>> --------------------------------------------------------------------- >>> To unsubscribe, e-mail: log4j-dev-unsubscr...@logging.apache.org >>> For additional commands, e-mail: log4j-dev-h...@logging.apache.org >>> >>> >> >> >> -- >> E-Mail: garydgreg...@gmail.com | ggreg...@apache.org >> <ggreg...@apache.org> >> Java Persistence with Hibernate, Second Edition >> <http://www.manning.com/bauer3/> >> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> >> Spring Batch in Action <http://www.manning.com/templier/> >> Blog: http://garygregory.wordpress.com >> Home: http://garygregory.com/ >> Tweet! http://twitter.com/GaryGregory >> >> >> > > > -- > E-Mail: garydgreg...@gmail.com | ggreg...@apache.org > Java Persistence with Hibernate, Second Edition > <http://www.manning.com/bauer3/> > JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> > Spring Batch in Action <http://www.manning.com/templier/> > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory > > > -- E-Mail: garydgreg...@gmail.com | ggreg...@apache.org Java Persistence with Hibernate, Second Edition <http://www.manning.com/bauer3/> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> Spring Batch in Action <http://www.manning.com/templier/> Blog: http://garygregory.wordpress.com Home: http://garygregory.com/ Tweet! http://twitter.com/GaryGregory