log4j:ERROR Attempted to append to closed appender named [*]

8785 단어 appender

During system running, sometimes we can see the error message from log4j log:
 
log4j:ERROR Attempted to append to closed appender named [*].

 
Here I would like to talk about one use case which could cause this problem.
 
Most of the components in our project could use log4j, and some of them could have duplicated log4j configuration file:
 
  • log4j.xml and log4j.properties

  • Here is a log4j.xml demo for my test:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
    	debug="false">
    
    	<!-- Main log file for general output from SSP server. -->
    	<appender name="SYSTEM"
    		class="com.gemalto.util.log4j.DailyMaxRollingFileAppender">
    		<param name="File" value="logs/logFromlog4jXMLAppender.log" />
    		<param name="Append" value="true" />
    		<param name="DatePattern" value="'.'yyyy-MM-dd" />
    		<param name="maxNumberOfDays" value="7" />
    		<layout class="org.apache.log4j.PatternLayout">
    			<param name="ConversionPattern" value="%d %-5p [GTO] [%c] %X{MSISDN} %X{IMEI} %m%n" />
    		</layout>
    	</appender>
    
    	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
    		<param name="Target" value="System.out" />
    		<param name="Threshold" value="INFO" />
    		<layout class="org.apache.log4j.PatternLayout">
    			<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" />
    		</layout>
    	</appender>
    
    	<category name="com.test" additivity="true">
    		<priority value="DEBUG" />
    		<appender-ref ref="SYSTEM" />
    	</category>
    
    
    	<root>
    		<priority value="INFO" />
    		<appender-ref ref="SYSTEM" />
    		<appender-ref ref="CONSOLE" />
    	</root>
    
    </log4j:configuration>
    

     
    Also, there is a log4j.properties in same location as log4j.xml:
    log4j.rootCategory=DEBUG, stdout
    log4j.logger.com=DEBUG, smsdriver
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
    
    log4j.appender.smsdriver=com.gemalto.util.log4j.DailyMaxRollingFileAppender
    log4j.appender.smsdriver.file=logs/logFromlog4jPropertiesAppender.log
    log4j.appender.smsdriver.append=true
    log4j.appender.smsdriver.layout=org.apache.log4j.PatternLayout
    log4j.appender.smsdriver.layout.ConversionPattern=%d %p [%c] - <%m> %F %n
    

     
    During our test, we will load log4j.xml first to configure Logger Hierarchy, and then load log4j.properties to configure Logger Hierarchy. We will see what happen according to logs.
    Here is the test code on log4j configuration:
    	@Test
    	public void testlog4jConfigurator() throws Exception {
    		System.setProperty("log4j.debug", "true");
    		Logger logger = org.apache.log4j.Logger
    				.getLogger("com.DOMConfigurator"); 
    		logger.info("Logger before DOMConfigurator."); //#1
    
    		System.setProperty("log4j.defaultInitOverride", "true");
    
    		URL log4jXml = TempTest.class.getResource("/log4j.xml");
    		URL log4jProperties = TempTest.class.getResource("/log4j.properties");
    
    		DOMConfigurator.configure(log4jXml);
    		Logger loggerDOMConfigurator = org.apache.log4j.Logger
    				.getLogger("com.DOMConfigurator");
    		loggerDOMConfigurator.info("Logger loggerDOMConfigurator.");//#2
    		// assertEquals(logger, loggerDOMConfigurator);
    		Logger loggerDOMConfigurator2 = org.apache.log4j.Logger
    				.getLogger("com.test.2");
    		Logger loggerDOMConfigurator3 = org.apache.log4j.Logger
    				.getLogger("com.test.3");
    
    		PropertyConfigurator.configureAndWatch(getFilePath(log4jProperties));
    		loggerDOMConfigurator.info("Logger loggerPropertyConfigurator."); //#3
    		// assertEquals(loggerPropertyConfigurator, loggerDOMConfigurator);
    
    		loggerDOMConfigurator2.info("Logger loggerDOMConfigurator2."); //#4
    		loggerDOMConfigurator3.info("Logger loggerDOMConfigurator3."); //#5
    	}
    

     
    By default, org.apache.log4j.LogManager will load "log4j.xml", so we can see #1 and #2 output into file: logs/logFromlog4jXMLAppender.log:
    2011-12-22 10:17:52,669 INFO [GTO] [com.DOMConfigurator] Logger before DOMConfigurator.
    2011-12-22 10:17:52,669 INFO [GTO] [com.DOMConfigurator] Logger loggerDOMConfigurator.
     
    #3 will output into file: logs/logFromlog4jPropertiesAppender.log:
    2011-12-22 10:17:52,684 INFO [com.DOMConfigurator] - Log4jTest.java
     
    #4 and #5 will be log into file logs/logFromlog4jPropertiesAppender.log because we configure a Category: log4j.logger.com. BUT we cannot see any log in logs/logFromlog4jXMLAppender.log. AND we will see the following errors in console:
    log4j:ERROR Attempted to append to closed appender named [SYSTEM].
    log4j:ERROR Attempted to append to closed appender named [SYSTEM].
    Why this situation comes? See
    log4j source code analyze.  Here I will list some solutions to solve this problem.

    Solutions


    Here I would like to list some workaround.

    1: Remove APPENDER ref from root category


    We can remove the appender-ref to "SYSTEM"in log4j.xml/root like following:
    	<category name="com.test" additivity="true">
    		<priority value="DEBUG" />
    		<appender-ref ref="SYSTEM" />
    	</category>
    
    
    	<root>
    		<priority value="INFO" />
    		<!--appender-ref ref="SYSTEM" /-->
    		<appender-ref ref="DMCONSOLE" />
    	</root>
    

     There won't be any error message refer to appender closed.  In this case, we can see #4 and #5 logs in both files.
    (Please be aware of that #2 won't be logged in this case.)

    2: Remvoe APPENDER ref in specific Category


    We can also remove the appender-ref to "SYSTEM"in log4j.xml/Category/com.test like following:
     
    	<category name="com.test" additivity="true">
    		<priority value="DEBUG" />
    		<!--appender-ref ref="SYSTEM" /-->
    	</category>
    
    
    	<root>
    		<priority value="INFO" />
    		<appender-ref ref="SYSTEM" />
    		<appender-ref ref="DMCONSOLE" />
    	</root>
    

     In this case, there also won't be any error message refer to "appender closed". But #4 and #5 will only be logged in file: logs/logFromlog4jPropertiesAppender.log.

    Conclusion


    As descript in  log4j , there will be only one Logger instance with specific name. Log4j allows logging requests to print to multiple destinations. In log4j speak, an output destination is called an appender. Currently, appenders exist for the console, files, GUI components, remote socket servers, JMS, NT Event Loggers, and remote UNIX Syslog daemons. It is also possible to log asynchronously.
    More than one appender can be attached to a logger. 
    The addAppender method adds an appender to a given logger. Each enabled logging request for a given logger will be forwarded to all the appenders in that logger as well as the appenders higher in the hierarchy.
     
    As we can see, Appender related to logger could be modified during second Configurator. So the error comes.
     

    좋은 웹페이지 즐겨찾기