That's not how I have now. I'll revisit... On Sep 14, 2016 4:27 PM, "Ralph Goers" <ralph.go...@dslextreme.com> wrote:
> A new Binding is created for every script execution so thread safety is > not a problem. > > Ralph > > On Sep 14, 2016, at 4:09 PM, Remko Popma <remko.po...@gmail.com> wrote: > > If the Binding is shared between threads (and therefore not thread-safe), > you could put the LogEvent in a ThreadLocal. > > Sent from my iPhone > > On 2016/09/15, at 6:24, Gary Gregory <garydgreg...@gmail.com> wrote: > > 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.goers@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 > > >