0
votes

I want to have different loggers in my program. Each Logger writes to a different file. The file names are predefined and it is not dynamic. For example, login package is going to use a logger that writes to a login.log file. Appenders all will be the same except the filename. Here is an example configuration file for a program that has two packages 'logging' and 'test':

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
 <Properties>
    <Property name="log-location"> /home/roya/workspace/LogPractice/log</Property>
</Properties>
  <Appenders>
    <RollingFile name="logging" fileName="${log-location}/logging.log"
          filePattern="${log-location}/$${date:yyyy-MM}/logging-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="1 KB"/>
      </Policies>
      <DefaultRolloverStrategy max="5">
        <!--
        Nested conditions: the inner condition is only evaluated on files
        for which the outer conditions are true.
        -->
        <Delete basePath="${log-location}" maxDepth="2">
          <IfFileName glob="*/app-*.log.gz">
            <IfLastModified age="30d">
              <IfAny>
                <IfAccumulatedFileSize exceeds="100 GB" />
                <IfAccumulatedFileCount exceeds="10" />
              </IfAny>
            </IfLastModified>
          </IfFileName>
        </Delete>
      </DefaultRolloverStrategy>
    </RollingFile>


    <RollingFile name="test" fileName="${log-location}/test.log"
          filePattern="${log-location}/$${date:yyyy-MM}/test-%d{yyyy-MM-dd-HH}-%i.log.gz">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <Policies>
        <TimeBasedTriggeringPolicy />
        <SizeBasedTriggeringPolicy size="1 KB"/>
      </Policies>
      <DefaultRolloverStrategy max="5">
        <!--
        Nested conditions: the inner condition is only evaluated on files
        for which the outer conditions are true.
        -->
        <Delete basePath="${log-location}" maxDepth="2">
          <IfFileName glob="*/app-*.log.gz">
            <IfLastModified age="30d">
              <IfAny>
                <IfAccumulatedFileSize exceeds="100 GB" />
                <IfAccumulatedFileCount exceeds="10" />
              </IfAny>
            </IfLastModified>
          </IfFileName>
        </Delete>
      </DefaultRolloverStrategy>
    </RollingFile>
    <Console name="Console" target="SYSTEM_OUT">
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
  </Appenders>
  <Loggers>
    <Logger name="logging">
     <AppenderRef ref="logging" level="ALL" />
    </Logger>
    <Logger name="test">
     <AppenderRef ref="test" level="ALL" />
    </Logger>
    <Root level="ALL">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

As you can see the appenders are the same except the filename. Is there a way that I define only one appender and just pass the filename to the Logger ?

2

2 Answers

1
votes

No, they are different Appender instances even though they are configured very similarly. Log4j 2 does not provide a mechanism to share parts of an Appender configuration.

One thing you can do to reduce duplication is to declare the Delete action only once (on one of the appenders, and make it match multiple files so it covers all appenders.

You can also raise a feature request on the log4j2 issue tracker or mailing list.

0
votes

I am not sure, if it may work, but it worth trying. You can extract the common appender fragment into separate file and use XInclude. Besides, the repeating part of the file pattern may be defined as a property. Both things will reduce the configuration line of codes dramatically.

This will look like this.

File log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
    <Property name="log-location"> /home/roya/workspace/LogPractice/log</Property>
    <Property name="dir">${log-location}/$${date:yyyy-MM}</Property>
    <Property name="ext">-%d{yyyy-MM-dd-HH}-%i.log.gz</Property>
</Properties>
<Appenders>
    <RollingFile name="logging" fileName="${log-location}/logging.log" 
      filePattern="${dir}/logging${ext}">
        <xi:include href="log4j-xinclude-appender-config.xml" />
    </RollingFile>

     <RollingFile name="test" fileName="${log-test}/test.log" 
      filePattern="${dir}/test${ext}">
        <xi:include href="log4j-xinclude-appender-config.xml" />
    </RollingFile>

    <Console name="Console" target="SYSTEM_OUT">
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>

File log4j-xinclude-appender-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
  <Policies>
    <TimeBasedTriggeringPolicy />
    <SizeBasedTriggeringPolicy size="1 KB"/>
  </Policies>
  <DefaultRolloverStrategy max="5">
    <!--
    Nested conditions: the inner condition is only evaluated on files
    for which the outer conditions are true.
    -->
    <Delete basePath="${log-location}" maxDepth="2">
      <IfFileName glob="*/app-*.log.gz">
        <IfLastModified age="30d">
          <IfAny>
            <IfAccumulatedFileSize exceeds="100 GB" />
            <IfAccumulatedFileCount exceeds="10" />
          </IfAny>
        </IfLastModified>
      </IfFileName>
    </Delete>
  </DefaultRolloverStrategy>