31

I have a web app that uses Spring's Log4jConfigurer class to initialize my Log4J log factory. Basically it initializes Log4J with a config file that is off the class path.

Here is the config:

<bean id="log4jInitializer" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" depends-on="sbeHome">
    <property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
    <property name="targetMethod" value="initLogging" />
    <property name="arguments">
        <list>
            <value>#{ MyAppHome + '/conf/log4j.xml'}</value>
        </list>
    </property>
</bean>

However I get this error at application startup:

log4j:WARN No appenders could be found for logger

and tons of Spring application context initialization messages are printed to the console. I think this is because Spring is doing work to initialize my application before it has a chance to initialize my logger. In case it matters, I am using SLF4J on top of Log4J.

Is there some way I can get my Log4jConfigurer to be the first bean initialized? or is there some other way to solve this?

Dave
  • 21,524
  • 28
  • 141
  • 221

5 Answers5

47

You could configure your Log4j listener in the web.xml instead of the spring-context.xml

<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/classes/log4j.web.properties</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

So it is up before Spring starts.

Crowie
  • 3,220
  • 7
  • 28
  • 48
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • I should have mentioned that my path to the log4J properties file is coming from a JNDI string. How can I supply that JNDI value to . If I could do that, I think I am all set. – Dave Dec 09 '10 at 16:46
  • 4
    I have found this: http://www.coderanch.com/t/362833/Servlets/java/log-ServletContextListener -- it shows how to implement your own log4j configuration listener which get some information by JNDI – Ralph Dec 09 '10 at 16:55
  • I created my own servlet context listener like they did and it all works perfectly. Thanks. – Dave Dec 09 '10 at 18:40
7

Our standalone application required an SMTPAppender where the email config already exists in a spring config file and we didn't want that to be duplicated in the log4j.properties.

I put the following together to add an extra appender using spring.

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <bean factory-method="getRootLogger"
              class="org.apache.log4j.Logger" />
    </property>
    <property name="targetMethod">
        <value>addAppender</value>
    </property>
    <property name="arguments">
        <list>
            <bean init-method="activateOptions"
                  class="org.apache.log4j.net.SMTPAppender">
                <property name="SMTPHost" ref="mailServer" />
                <property name="from" ref="mailFrom" />
                <property name="to" ref="mailTo" />
                <property name="subject" ref="mailSubject" />
                <property value="10" name="bufferSize" />
                <property name="layout">
                    <bean class="org.apache.log4j.PatternLayout">
                        <constructor-arg>
                            <value>%d, [%5p] [%t] [%c] - %m%n</value>
                        </constructor-arg>
                    </bean>
                </property>
                <property name="threshold">
                    <bean class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"
                          id="org.apache.log4j.Priority.ERROR" />
                </property>
            </bean>
        </list>
    </property>
</bean>

We also have a log4j.properties file on the classpath which details our regular FileAppenders.

I realise this may be overkill for what you require :)

Harry Lime
  • 29,476
  • 4
  • 31
  • 37
4

Rather than configuring log4j yourself in code, why not just point log4j at your (custom) configuration file's location by adding

-Dlog4j.configuration=.../conf/log4j.xml

to your server's startup properties?

Even better, just move log4j.xml to the default location - on the classpath - and let log4j configure itself automatically.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • 4
    I'm trying to keep the log4j file outside of the WAR so that we can have customer's easily tweak it as needed for problem diagnosis. As to the JVM property, currently we don't even have a startup script. Customers just deploy the WAR file and go. – Dave Dec 09 '10 at 16:51
  • In some cases we should add "file" prefix to path `-Dlog4j.configuration=file:conf/log4j.properties` – Fırat Küçük Jul 26 '14 at 07:27
  • @matt b please clarify classpath sequence scanninng – gstackoverflow Aug 30 '16 at 07:00
2

You can use classpath instead of hardcoded path. It works for me

<bean id="log4jInitializer" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" depends-on="sbeHome">
    <property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
    <property name="targetMethod" value="initLogging" />
    <property name="arguments">
        <list>
            <value>classpath:/conf/log4j.xml</value>
        </list>
    </property>
</bean>
Dan Grahn
  • 9,044
  • 4
  • 37
  • 74
ravi ranjan
  • 5,920
  • 2
  • 19
  • 18
1

If you are using Jetty you can add extra classpaths on a per application basis:

http://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading#Adding_Extra_Classpaths_to_Jetty

This will allow you to load your log4 properties in a standard manner (from the classpath:)

in web.xml:

       <listener>
           <listener-class>org.springframework.web.util.Log4jWebConfigurer</listener-class>
       </listener>
       <context-param>
           <param-name>log4jConfigLocation</param-name>
           <param-value>classpath:${project.artifactId}-log4j.properties</param-value>
       </context-param>

in jetty-web.xml:

        <Set name="extraClasspath">
            <SystemProperty name="config.home" default="."/>/contexts/log4j
        </Set>
Mond Raymond
  • 320
  • 1
  • 4
  • 9