After reviewing what I wrote below and looking at the Routing Appender I think 
the best thing to do is just to add script support to it.  It already has 
support for a default Route. The init script, if present, could override which 
Route to use as I described below. Then we could add a script attribute to the 
Routes plugin which could be used to select the Route instead of only matching 
on the ThreadContext key.

With that I think you would have everything you want, plus it could be used as 
a more intelligent way to route to existing appenders.

The configuration would then look like:

  <Appenders>
    <Console name="STDOUT" target="SYSTEM_OUT">
      <PatternLayout pattern="%m%n"/>
    </Console>
    <Flume name="AuditLogger" compress="true">
      <Agent host="192.168.10.101" port="8800"/>
      <Agent host="192.168.10.102" port="8800"/>
      <RFC5424Layout enterpriseNumber="18060" includeMDC="true" 
appName="MyApp"/>
    </Flume>
    <Routing name=?Routing?>
      <InitScript name=?RoutingInit" language="groovy"><![CDATA[
         if (System.getProperty(?os.name?).contains(?OS/390") {
            return “OS390";
         }
         return null;]]>
      </InitScript>
      <Routes>     
        <Script name="Router" language="groovy"><![CDATA[
            if (logEvent.getMarker() != null && 
logEvent.getMarker().isInstanceOf("AUDIT")) {
                return "AUDIT";
            } else if (logEvent.getContextMap().containsKey("UserId")) { 
                return logEvent.getContextMap().get("UserId");
            }
            return "STDOUT";
            ]]>
          </Script> 
        <Route>
          <OS390Appender name=“OS390-${mdc:UserId”/> 
          <RollingFile name="Rolling-${mdc:UserId}" fileName="${mdc:UserId}.log"
                       filePattern="${mdc:UserId}.%i.log.gz">
            <PatternLayout>
              <pattern>%d %p %c{1.} [%t] %m%n</pattern>
            </PatternLayout>
            <SizeBasedTriggeringPolicy size="500" />
          </RollingFile>
        </Route>
        <Route ref="AuditLogger" key="Audit"/>
        <Route ref="STDOUT" key="STDOUT"/>
      </Routes>
      <IdlePurgePolicy timeToLive="15" timeUnit="minutes"/>
    </Routing>
  </Appenders>
First, the init script changes the default route based on the OS.
Second, notice that “Routes” has a new Script element and does not have a 
pattern specified, so the script is determining the key instead of the pattern. 
Third, the real default route is now “STDOUT” since the actual default Route is 
only referenced when a UserId is present in the thread context map.

What would also be nice is if there was a way to have the returned value be 
usable as a Lookup value in the default Appender definition, instead of relying 
on the MDC as the code above does. I should be able to pick something out of 
the message itself and use that as the key. That should be doable but I am 
still pondering how I would implement that.

Ralph



> On Sep 12, 2016, at 6:06 PM, Ralph Goers <ralph.go...@dslextreme.com> wrote:
> 
> I’ll try to describe it better but I’m not sure how good a job I’ll do if the 
> dots aren’t clicking yet. Also, even though I might say to do it one way if I 
> was coding I could very well change my mind as I implement it. That said:
> Create an Appender plugin named ScriptSelector or ScriptAppenderSelector. It 
> needs the following parameters
> name, a String PluginAttribute
> default, a String PluginAttribute
> initScript or startupScript, an AbstractScript PluginElement
> script, an AbstractScript PluginElement
> appenderList, an AppenderList PluginElement.
> As always, the builder (or factory) creates an instance of the 
> ScriptAppenderSelector. 
> If there is an init script then the builder (or factory) executes it. 
> If the returned value is not null then instantiate the Appender with that 
> name using the configuration in the AppenderList. 
> Whatever Appender the init script names should become the default Appender.
> If no init script is present or the init script returns null use the value of 
> the default setting as the name of the default Appender to use.
> Create the default Appender and save it in the Map of created appenders 
> wrapped by an AppenderControl.
> When the append method is called check for a script setting.
> If a script is found, run it. 
> If it returns a value see if that appender is saved in the AppenderMap. 
> If it is, call the appender and return.
> If it is not, locate the configuration for the appender, create it and add it 
> to the AppenderMap. Then call it and return.
> If it returns null or no script is defined then call the default Appender and 
> return.
> When the stop method is called call the stop method on each of the Appenders 
> in the AppenderMap.
> 
> Note that signatures for scripts are defined by the components that use them. 
> In this case both the init script and script return the name of the appender 
> to execute. 
> 
> Ralph
> 
> 
>> On Sep 12, 2016, at 12:54 PM, Gary Gregory <garydgreg...@gmail.com 
>> <mailto:garydgreg...@gmail.com>> wrote:
>> 
>> On Sun, Sep 11, 2016 at 12:47 PM, Ralph Goers <ralph.go...@dslextreme.com 
>> <mailto:ralph.go...@dslextreme.com>> wrote:
>> Yes. The Appenders tag inside the ScriptSelector are the Appenders that are 
>> to be created. But now that I think about it, we can’t use “Appenders” for 
>> this. If you look at the RoutingAppender you will notice that Appenders 
>> there are declared under a Route element. The Route plugin is defined with 
>> deferChildren=true. This means that whatever is configured under the Route 
>> will not be created during initial configuration. Instead the Route keeps a 
>> reference to the Node and then configures the Appender when it is required. 
>> So we would need a new plugin to wrap the Appenders that are to be created.
>> 
>> Can you please describe in more detail how this new plug fits in and what it 
>> does? I can't quite connect the dots with the parallel of the routing 
>> appender. I'm willing to implement this as I need the feature ASAP. 
>> 
>> Gary
>> 
>> 
>> Ralph
>> 
>>> On Sep 11, 2016, at 11:10 AM, Gary Gregory <garydgreg...@gmail.com 
>>> <mailto:garydgreg...@gmail.com>> wrote:
>>> 
>>> Are the <Appenders> tags really meant to be nested?
>>> 
>>> Gary
>>> 
>>> On Sat, Sep 10, 2016 at 11:48 AM, Ralph Goers <ralph.go...@dslextreme.com 
>>> <mailto:ralph.go...@dslextreme.com>> wrote:
>>> Oops. I forgot the closing CDATA tag in the script.
>>> 
>>> Ralph
>>> 
>>>> On Sep 10, 2016, at 11:43 AM, Ralph Goers <ralph.go...@dslextreme.com 
>>>> <mailto:ralph.go...@dslextreme.com>> wrote:
>>>> 
>>>> Interesting. OS/390.  I worked on MVS, OS/370, z/OS, etc many moons ago 
>>>> but haven’t worked on a mainframe since 2001.
>>>> 
>>>> This sort of sounds like you want an Appender Selector, which would be an 
>>>> Appender that uses a Selector to figure out which Appender to delegate to. 
>>>> This is a bit like the PatternSelector. I would imagine it would make 
>>>> sense to implement AppenderSelectors and LayoutSelectors.  You probably 
>>>> would want to dynamically initialize the Appenders much like the 
>>>> RoutingAppender does. 
>>>> 
>>>> Maybe it would look like:
>>>> 
>>>> <Appenders>
>>>>   <ScriptSelector name=“" default=“”>
>>>>      <Script language=“groovy”><![CDATA[
>>>>          if (System.getProperty”os.name 
>>>> <http://os.name/>”).contains(“OS/390”)) then {
>>>>              return “Socket”;
>>>>          } else {
>>>>              return “File”;
>>>>          }           
>>>>      </Script>
>>>>      <Appenders>
>>>>          <SocketAppender name=“Socket” …/>
>>>>          <FileAppender name=“File” …/>
>>>>      </Appenders>     
>>>>   </ScriptSelector>
>>>> </Appenders>
>>>> 
>>>> The thing is that this script would run every time the Selector was 
>>>> accessed while it sounds like you would only want the script to run when 
>>>> the Selector is initialized. We could do that too but the script would 
>>>> need to be declared in a property that would only be used when the 
>>>> selector is initialized. I would want to support being able to do both.
>>>> 
>>>> Ralph
>>>> 
>>>>> On Sep 10, 2016, at 11:04 AM, Gary Gregory <garydgreg...@gmail.com 
>>>>> <mailto:garydgreg...@gmail.com>> wrote:
>>>>> 
>>>>> <Appenders>
>>>>>    <ScriptTest language="JavaScript">
>>>>>       <If>System.getProperty("os.name 
>>>>> <http://os.name/>").contains("OS/390")</If>
>>>>>       <True>
>>>>>          <SocketAppender ...>
>>>>>      </True>
>>>>>      <False>
>>>>>          <FileAppender ...>
>>>>>      </False>
>>>>>    </ScriptTest>
>>>>> </Appenders>
>>>>> 
>>>>> ?
>>>>> 
>>>>> 
>>>>> On Sat, Sep 10, 2016 at 10:40 AM, Gary Gregory <garydgreg...@gmail.com 
>>>>> <mailto:garydgreg...@gmail.com>> wrote:
>>>>> OK, I found 
>>>>> https://logging.apache.org/log4j/2.x/manual/configuration.html#Scripts 
>>>>> <https://logging.apache.org/log4j/2.x/manual/configuration.html#Scripts> 
>>>>> and I think I could use either:
>>>>> 
>>>>> - Use composite configurations: One file for OS/390, one for all other 
>>>>> OSs; or
>>>>> - Do it all in one configuration file (that seems simpler)
>>>>> 
>>>>> It seems like there are some pieces missing to do what I want 
>>>>> conveniently.
>>>>> 
>>>>> Should I define all appenders in <Appenders> and later use a script to 
>>>>> only add the one(s) I want in the <Root> section?
>>>>> 
>>>>> Or, should the <Appenders> section itself be scripted to only add the 
>>>>> appenders I want? 
>>>>> 
>>>>> Since I expect the OS/390 appender will likely blow up running on a 
>>>>> different OK I do not want to create it unless I know it can run OK. 
>>>>> 
>>>>> I guess then I have a conditional section in both the Appenders and in 
>>>>> the Root section so that when I say <AppenderRef =...> we do not go look 
>>>>> for an appender that is not defined.
>>>>> 
>>>>> Thoughts?
>>>>> 
>>>>> A narrow solution would be to add an "os" attribute to all appenders but 
>>>>> that seems lame. os="OS/390" and os="!OS/390" means also knowing about 
>>>>> "not", yikes.
>>>>> 
>>>>> Gary
>>>>> 
>>>>> On Sat, Sep 10, 2016 at 10:05 AM, Gary Gregory <garydgreg...@gmail.com 
>>>>> <mailto:garydgreg...@gmail.com>> wrote:
>>>>> Hi,
>>>>> 
>>>>> I can't seem to find on our site the scripting support that was recently 
>>>>> added (or is that only in master?).
>>>>> 
>>>>> What I need to do is only add a specific appender when running on a 
>>>>> specific OS (USS on OS/390 if you must know). Then only add a different 
>>>>> appender when not running on that OS.
>>>>> 
>>>>> I'd rather not have to hard-code this and make thing more complicated.
>>>>> 
>>>>> Thoughts?
>>>>> 
>>>>> Gary
>>>>> 
>>>>> -- 
>>>>> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
>>>>> ggreg...@apache.org  <mailto: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 
>>>>> <http://garygregory.wordpress.com/> 
>>>>> Home: http://garygregory.com/ <http://garygregory.com/>
>>>>> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>
>>>>> 
>>>>> 
>>>>> -- 
>>>>> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
>>>>> ggreg...@apache.org  <mailto: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 
>>>>> <http://garygregory.wordpress.com/> 
>>>>> Home: http://garygregory.com/ <http://garygregory.com/>
>>>>> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>
>>>>> 
>>>>> 
>>>>> -- 
>>>>> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
>>>>> ggreg...@apache.org  <mailto: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 
>>>>> <http://garygregory.wordpress.com/> 
>>>>> Home: http://garygregory.com/ <http://garygregory.com/>
>>>>> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>
>>> 
>>> 
>>> 
>>> 
>>> -- 
>>> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
>>> ggreg...@apache.org  <mailto: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 <http://garygregory.wordpress.com/> 
>>> Home: http://garygregory.com/ <http://garygregory.com/>
>>> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>
>> 
>> 
>> 
>> -- 
>> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
>> ggreg...@apache.org  <mailto: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 <http://garygregory.wordpress.com/> 
>> Home: http://garygregory.com/ <http://garygregory.com/>
>> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>

Reply via email to