1

I'm migrating from log4j 1.x to 2.x and we have a properties file "foo.properties" which we read in spring's applicationContext.xml and turn into system properties:

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="foo" value="classpath:META-INF/properties/foo.properties" />
    </bean>

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject">
            <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                <property name="targetClass" value="java.lang.System" />
                <property name="targetMethod" value="getProperties" />
            </bean>
        </property>
        <property name="targetMethod" value="putAll" />
        <property name="arguments">
            <util:properties>
                <prop key="x.y.z">${x.y.z}</prop>
                <prop key="a.b.c">${a.b.c}</prop>
                ...
        </util:properties>
        </property>
    </bean>

I would expect to be able now to reference x.y.z in log4j2.xml like <RollingFile name="rollingFile" fileName="${sys:x.y.z}">, however this doesn't work with 2.x. With 1.x ${x.y.z} works fine.

Previously, we had this code in applicationContext.xml to initialize log4j:

    <bean id="log4jInitialization"
        class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
        <property name="targetMethod" value="initLogging" />
        <property name="arguments">
            <list>
                <value>classpath:log4jMain.xml</value>
            </list>
        </property>
    </bean>

But this was removed because it does not apply for 2.x, which may have broken something. How can I get log4j2 to lookup a system property set by Spring?

krsong
  • 13
  • 3

1 Answers1

0

If you are using Spring Boot Log4j will initialize at least 3 times, with the first being before Spring has done anything. So it would be impossible for Spring to set those properties for you. However, subsequent calls to initialize logging might be able to provide the properties but it isn't really necessary as Log4j can handle this for you.

Option 1 - If you are using Spring Boot then include the Log4j Spring Cloud Config Client. It includes a SpringLookup that will let you reference any property defined in a Spring configuration. For example, if you have an application.yaml that contains:

logging:
  root:
    level:

You could reference ${spring:logging.root.level} in the log4j2.xml file.

Option 2 - If you are not using Spring Boot or prefer system properties then you can create a file named log4j2.system.properties on the classpath. All properties found in this file will be published by Log4j as system properties at the beginning of Log4j initialization.

rgoers
  • 8,696
  • 1
  • 22
  • 24
  • The reason I am doing it this way is because we have some other stuff going on in the CI/CD pipeline that I can't necessarily control, which ends up creating "foo.properties". It sounds like it only worked with 1.x because of the reinitialization with MethodInvokingFactoryBean. Is there a comparable method I could call to reinitialize 2.x? Or, is there some property I could set to change the filename used for log4j2.system.properties? I tried to look for it in the documentation but couldn't find anything. Thanks for the help! – krsong Jul 04 '20 at 15:14
  • No, you cannot change the name of the log4j2.system.properties file. Yes, if you were reinitializing logging then that would have cause those properties to be available during that reconfiguration. Yes, you can cause Log4j to reconfigure. See the Configurator class. However, I would suggest you change your CI/CD pipeline instead of mucking with your application startup. Tailoring your application to match your CI/CD pipeline feels like the tail wagging the dog. – rgoers Jul 04 '20 at 16:38
  • I found the commit that added support for log4j2.system.properties file (by you!) 14 months ago, but unfortunately that is too recent for me to use. I am stuck on log4j2 2.7 because we use Tomcat 7 and it can't handle some class file features of newer versions. I also can't use Configurator.reconfigure() for the same reason since that is only available since 2.12. Do you know if there is any other way to accomplish this or some workaround to use newer versions w/ Tomcat 7? – krsong Jul 06 '20 at 17:28
  • Tomcat 7 will run with on Java 8 (I have many apps that do that) but maybe you have other dependencies that aren't compatible? – rgoers Jul 06 '20 at 17:35
  • I am running Tomcat 7 / Java SE 8 but I get an error about "org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19" on startup. I was just following this answer which says to downgrade log4j2 version: https://stackoverflow.com/questions/54578459/tomcat-7-annotations-in-log4j-api-2-11-1-jar and it got rid of it. Can I just ignore that error and safely run latest log4j2 version? – krsong Jul 06 '20 at 17:53