[ 
https://issues.apache.org/jira/browse/LOG4J2-3469?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jody Garnett updated LOG4J2-3469:
---------------------------------
    Description: 
 

The documentation covers both [Initialize Log4j by Combining Configuration File 
with Programmatic 
Configuration|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Hybrid]
 and [Programmatically Modifying the Current Configuration after 
Initialization|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Programmatically_Modifying_the_Current_Configuration_after_Initialization].
 

However both these techniques are limited as to what they can accomplish:
 * MyXMLConfiguration.doConfigure() is shown adding an appender, via addLogger 
method
 * A custom configuration super.setup() method is shown using 
config.addLogger() and then ctx.updateLoggers().

My challenge is to programatically update the configuration to:
 * Override logfile output location, either directly modifying appender, or 
modifying config property used by appender.
 * Optionally Filter out any RollingFileAppender or FileAppender appenders
 * Optionally suppress (filter out) any Console loggers if asked

I am seeking an api used to pre-process configuration objects if one is 
available.

In the past when using a fluent / builder API there is an option to jump-start 
a builder with the configuration of an existing object. This approach would 
allow a builder to be loaded with an existing appender; revised, and a new 
appender generated as a replacement.
{code:java}
@Override protected void doConfigure() {
    super.doConfigure();

    getProperties().put("GEOSERVER_LOG_LOCATION","geoserver.log");

    Appender appender = getAppenders("geoserverlogfile");
    if( appender instanceof RollingFileAppender){
         RollingFileAppender fileAppender =(RollingFileAppender) appender;

         RollingFileAppender replacement = 
RollingFileAppender.newBuilder(fileAppender)
            .withFileName("${GEOSERVER_LOG_LOCATION}.log")
            .withFilePattern("${GEOSERVER_LOG_LOCATION}-%i.log")
            .build();
        
         getAppenders().remove("geoserverlogfile");
         addAppender(replacement);
    }
}{code}
The alternative is verbose and may miss copying new parameters added over time.

Alternatives considered:

*MyXMLConfiguration.setup()* prior to super.setup(): Unclear how easy/safe it 
is to to modify _rootNode_ structure directly? Is this what is intended by the 
documentation.
{code:java}
public void setup() {
    for( Node child : rootNode.getChildren()){
        if ("Properties".equals(child.getName())){
            for( Node property : child.getChildren() ){
                if( property.getAttributes().containsKey("name") &&
                        
property.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
                    // override value with current GEOSERVER_LOG_LOCATION
                    property.setValue("foo.log");
                }
            }
        }
    }
    super.setup();
}{code}
*MyXMLConfiguration.doConfigure()* before super.doConfigure(): should be able 
to modify _rootNode_ and make any changes required. Unclear how easy/safe it is 
to to modify node structure directly?

*MyXMLConfiguration.doConfigure()*  after super.doConfigure(): is too late as 
shown above.
 - Can add loggers and appenders
 - Modifications to config.getProperties() are not reflected in appender 
configuration 
 - Modifications to existing appenders cannot be accomplished

{*}MyXMLConfiguration.{*}{*}preConfigure(Node){*} allows xml to be rewritten 
just-in-time:
{code:java}
@Overrideprotected void preConfigure(Node node) {
    if( !node.isRoot() && node.getName().equals("Property")){
        if( node.getAttributes().containsKey("name") &&
                
node.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
            // override value with current GEOSERVER_LOG_LOCATION
            node.setValue("foo.log");
        }
    }
    super.preConfigure(node);
} {code}
For reference see attached {*}DEFAULT_LOGGING.xml{*}.

  was:
 

The documentation covers both [Initialize Log4j by Combining Configuration File 
with Programmatic 
Configuration|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Hybrid]
 and [Programmatically Modifying the Current Configuration after 
Initialization|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Programmatically_Modifying_the_Current_Configuration_after_Initialization].
 

However both these techniques are limited as to what they can accomplish:
 * MyXMLConfiguration.doConfigure() is shown adding an appender, via addLogger 
method
 * A custom configuration super.setup() method is shown using 
config.addLogger() and then ctx.updateLoggers().

My challenge is to programatically update the configuration to:
 * Override logfile output location, either directly modifying appender, or 
modifying config property used by appender.
 * Optionally Filter out any RollingFileAppender or FileAppender appenders
 * Optionally suppress (filter out) any Console loggers if asked

I am seeking an api used to pre-process configuration objects if one is 
available.

In the past when using a fluent / builder API there is an option to jump-start 
a builder with the configuration of an existing object. This approach would 
allow a builder to be loaded with an existing appender; revised, and a new 
appender generated as a replacement.
{code:java}
@Override protected void doConfigure() {
    super.doConfigure();

    final LoggerContext context = (LoggerContext) LogManager.getContext(false);
    final Configuration config = context.getConfiguration();

    config.getProperties().put("GEOSERVER_LOG_LOCATION","geoserver.log");

    ConfigurationBuilder<BuiltConfiguration> builder =
       ConfigurationBuilderFactory.newConfigurationBuilder();

    Appender appender = config.getAppenders("geoserverlogfile");
    if( appender instanceof RollingFileAppender){
         RollingFileAppender fileAppender =(RollingFileAppender) appender;
    
        AppenderComponentBuilder appenderBuilder = builder.
            newAppender("geoserverlogfile", fileAppender)
                .addAttribute("fileName", "${GEOSERVER_LOG_LOCATION}.log");
        
        config.getAppenders().remove("geoserverlogfile");
        addAppender((Appender) appenderBuilder.build());
    }
}{code}
The alternative is verbose and may miss copying new parameters added over time.

Alternatives considered

*MyXMLConfiguration.setup()* prior to super.setup(): Unclear how easy/safe it 
is to to modify _rootNode_ structure directly? Is this what is intended by the 
documentation.
{code:java}
public void setup() {
    for( Node child : rootNode.getChildren()){
        if ("Properties".equals(child.getName())){
            for( Node property : child.getChildren() ){
                if( property.getAttributes().containsKey("name") &&
                        
property.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
                    // override value with current GEOSERVER_LOG_LOCATION
                    property.setValue("foo.log");
                }
            }
        }
    }
    super.setup();
}{code}
*MyXMLConfiguration.doConfigure()* before super.doConfigure(): should be able 
to modify _rootNode_ and make any changes required. Unclear how easy/safe it is 
to to modify node structure directly?

*MyXMLConfiguration.doConfigure()*  after super.doConfigure(): is too late as 
shown above.
 - Can add loggers and appenders
 - Modifications to config.getProperties() are not reflected in appender 
configuration 
 - Modifications to existing appenders cannot be accomplished

{*}MyXMLConfiguration.{*}{*}preConfigure(Node){*} allows xml to be rewritten 
just-in-time:
{code:java}
@Overrideprotected void preConfigure(Node node) {
    if( !node.isRoot() && node.getName().equals("Property")){
        if( node.getAttributes().containsKey("name") &&
                
node.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
            // override value with current GEOSERVER_LOG_LOCATION
            node.setValue("foo.log");
        }
    }
    super.preConfigure(node);
} {code}
For reference see attached {*}DEFAULT_LOGGING.xml{*}.


> Create new AppenderComponentBuilder from existing Appender
> ----------------------------------------------------------
>
>                 Key: LOG4J2-3469
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-3469
>             Project: Log4j 2
>          Issue Type: New Feature
>          Components: Configuration, Configurators, Core
>    Affects Versions: 2.17.2
>            Reporter: Jody Garnett
>            Priority: Minor
>         Attachments: DEFAULT_LOGGING.xml
>
>
>  
> The documentation covers both [Initialize Log4j by Combining Configuration 
> File with Programmatic 
> Configuration|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Hybrid]
>  and [Programmatically Modifying the Current Configuration after 
> Initialization|https://logging.apache.org/log4j/2.x/manual/customconfig.html#Programmatically_Modifying_the_Current_Configuration_after_Initialization].
>  
> However both these techniques are limited as to what they can accomplish:
>  * MyXMLConfiguration.doConfigure() is shown adding an appender, via 
> addLogger method
>  * A custom configuration super.setup() method is shown using 
> config.addLogger() and then ctx.updateLoggers().
> My challenge is to programatically update the configuration to:
>  * Override logfile output location, either directly modifying appender, or 
> modifying config property used by appender.
>  * Optionally Filter out any RollingFileAppender or FileAppender appenders
>  * Optionally suppress (filter out) any Console loggers if asked
> I am seeking an api used to pre-process configuration objects if one is 
> available.
> In the past when using a fluent / builder API there is an option to 
> jump-start a builder with the configuration of an existing object. This 
> approach would allow a builder to be loaded with an existing appender; 
> revised, and a new appender generated as a replacement.
> {code:java}
> @Override protected void doConfigure() {
>     super.doConfigure();
>     getProperties().put("GEOSERVER_LOG_LOCATION","geoserver.log");
>     Appender appender = getAppenders("geoserverlogfile");
>     if( appender instanceof RollingFileAppender){
>          RollingFileAppender fileAppender =(RollingFileAppender) appender;
>          RollingFileAppender replacement = 
> RollingFileAppender.newBuilder(fileAppender)
>             .withFileName("${GEOSERVER_LOG_LOCATION}.log")
>             .withFilePattern("${GEOSERVER_LOG_LOCATION}-%i.log")
>             .build();
>         
>          getAppenders().remove("geoserverlogfile");
>          addAppender(replacement);
>     }
> }{code}
> The alternative is verbose and may miss copying new parameters added over 
> time.
> Alternatives considered:
> *MyXMLConfiguration.setup()* prior to super.setup(): Unclear how easy/safe it 
> is to to modify _rootNode_ structure directly? Is this what is intended by 
> the documentation.
> {code:java}
> public void setup() {
>     for( Node child : rootNode.getChildren()){
>         if ("Properties".equals(child.getName())){
>             for( Node property : child.getChildren() ){
>                 if( property.getAttributes().containsKey("name") &&
>                         
> property.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
>                     // override value with current GEOSERVER_LOG_LOCATION
>                     property.setValue("foo.log");
>                 }
>             }
>         }
>     }
>     super.setup();
> }{code}
> *MyXMLConfiguration.doConfigure()* before super.doConfigure(): should be able 
> to modify _rootNode_ and make any changes required. Unclear how easy/safe it 
> is to to modify node structure directly?
> *MyXMLConfiguration.doConfigure()*  after super.doConfigure(): is too late as 
> shown above.
>  - Can add loggers and appenders
>  - Modifications to config.getProperties() are not reflected in appender 
> configuration 
>  - Modifications to existing appenders cannot be accomplished
> {*}MyXMLConfiguration.{*}{*}preConfigure(Node){*} allows xml to be rewritten 
> just-in-time:
> {code:java}
> @Overrideprotected void preConfigure(Node node) {
>     if( !node.isRoot() && node.getName().equals("Property")){
>         if( node.getAttributes().containsKey("name") &&
>                 
> node.getAttributes().get("name").equals("GEOSERVER_LOG_LOCATION")) {
>             // override value with current GEOSERVER_LOG_LOCATION
>             node.setValue("foo.log");
>         }
>     }
>     super.preConfigure(node);
> } {code}
> For reference see attached {*}DEFAULT_LOGGING.xml{*}.



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to