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-log4j2/ > 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/ > appender/routing/Routes.java > > index c95b64a..33fccd7 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,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. > 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.config.plugins.validation. > constraints.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/appender/routing/RoutingAppender.java > > index 4471333..78fddbc 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 > > @@ -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.getScriptManager().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/appender/routing/ > RoutesScriptAppenderTest.java > > new file mode 100644 > > index 0000000..7d90f6b > > --- /dev/null > > +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/ > appender/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(configLocation); > > + } > > + > > + 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( > RoutesScriptAppenderTest.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/resources/log4j-routing-routes-script-groovy.xml > b/log4j-core/src/test/resources/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/resources/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 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