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

 

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] - <Logger loggerPropertyConfigurator.> 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.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值