Log4j 2
  1. Log4j 2
  2. LOG4J2-129

RoutingAppender dynamic appender creation only creates 1

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0-beta3
    • Fix Version/s: 2.0-beta4
    • Component/s: Appenders
    • Labels:
      None

      Description

      I was looking through the new appenders and found RoutingAppender which intrigued me

      http://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender

      From the documentation it seems that the RoutingAppender would create a new appender dynamically every time the key didn't match an existing appender name. However when testing this I find it only creates the first dynamically and then reuses that one as it is set to default. That doesn't seem what I would expect. My example code is as the following:

      public class TestRouting {
          public static void main(String[] args) {
              ThreadContext.put("filename", "foo.bar");
              _logger.info("TEST");
              ThreadContext.put("filename", "foo.bar2");
              _logger.info("TEST2");
              ThreadContext.remove("filename");
          }
      
          private final static Logger _logger = LogManager.getLogger(TestRouting.class);
      }
      

      Here is the log4j2 xml file it picks up.

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <appenders>
          <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        
          <Routing name="RoutingAppender">
            <Routes pattern="${ctx:filename}">
              <Route>
                <RollingFile name="Rolling-${ctx:filename}" fileName="${ctx:filename}"
                             filePattern="${ctx:filename}.%i.log.gz">
                  <PatternLayout>
                    <pattern>%d %p %C{1.} [%t] %m%n</pattern>
                  </PatternLayout>
                  <SizeBasedTriggeringPolicy size="500" />
                </RollingFile>
              </Route>
            
              <!-- By having this set to ${ctx:filename} it will match when filename
                   is not set in the context -->
              <Route ref="Console" key="${ctx:filename}"/>
            
            </Routes>
          </Routing>
        </appenders>
          
        <loggers>
          <root level="info">
            <appender-ref ref="RoutingAppender"/>
          </root>
        </loggers>
      </configuration>
      

      When I run the test though it only creates 1 file/appender with the name foo.bar and logs both messages to it. I would expect that it creates 2 files where each gets the different message.

      Is there something I am missing about this or is this the intended behavior?

      I have a change that gets it working, however part of it is hack and would need to be updated to the best alternative. Also I had to change BaseConfiguration slightly to make a defensive copy of the attributes. It seemed that was fine, otherwise the Route cannot be reused to make another appender if it blows away the attributes, don't know if that will affect other things though.

      1. patch
        6 kB
        William Burns
      2. LOG4J2-129-RoutingAppender.patch
        8 kB
        Ingo Feltes
      3. LOG4J2-129-RoutingAppenderTest.patch
        1 kB
        Ingo Feltes

        Activity

        Hide
        William Burns added a comment -

        Patch with changes to get it working to create multiple appenders.

        Show
        William Burns added a comment - Patch with changes to get it working to create multiple appenders.
        Hide
        Ingo Feltes added a comment -

        When I read the documentation I also thought that a new appender should dynamically be created for each unkown key.

        Instead of changing the BaseConfiguration, I think the node should be cloned before the appender is created. Please find an updated patch attached.

        Show
        Ingo Feltes added a comment - When I read the documentation I also thought that a new appender should dynamically be created for each unkown key. Instead of changing the BaseConfiguration, I think the node should be cloned before the appender is created. Please find an updated patch attached.
        Hide
        Ralph Goers added a comment -

        The problem was that the code was treating the Appender being created under the default Route as the default. That is incorrect. The code has been modified to just keep track of the default route.

        Note that the configuration in your example is incorrect in that the key for "Console" needs to be a value and not a variable. In addition, the variable declaration in the Routes pattern should be $$

        {ctx:filename}

        .

        You can look at log4j-routing.xml for an example, however it is similar to the documentation on the web site.

        Please verify and close.

        Show
        Ralph Goers added a comment - The problem was that the code was treating the Appender being created under the default Route as the default. That is incorrect. The code has been modified to just keep track of the default route. Note that the configuration in your example is incorrect in that the key for "Console" needs to be a value and not a variable. In addition, the variable declaration in the Routes pattern should be $$ {ctx:filename} . You can look at log4j-routing.xml for an example, however it is similar to the documentation on the web site. Please verify and close.
        Hide
        Ingo Feltes added a comment -

        The implementation seems to work correctly now, but the test cleans up the wrong files. See attached patch.

        Show
        Ingo Feltes added a comment - The implementation seems to work correctly now, but the test cleans up the wrong files. See attached patch.
        Hide
        William Burns added a comment -

        Just reread your comment again.

        I wanted to clarify on the Console Appender using a variable for the key. The reason is because the replacement won't occur if the context value isn't present so then the console will be matched to thread contexts that don't have a value set for filename in this case. Is there a better way you can recommend?

        Thanks.

        Show
        William Burns added a comment - Just reread your comment again. I wanted to clarify on the Console Appender using a variable for the key. The reason is because the replacement won't occur if the context value isn't present so then the console will be matched to thread contexts that don't have a value set for filename in this case. Is there a better way you can recommend? Thanks.

          People

          • Assignee:
            Ralph Goers
            Reporter:
            William Burns
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development