Bug 33708 - XML Configuration of loggerFactory does not work
Summary: XML Configuration of loggerFactory does not work
Alias: None
Product: Log4j - Now in Jira
Classification: Unclassified
Component: Configurator (show other bugs)
Version: 1.2
Hardware: PC Linux
: P2 major
Target Milestone: ---
Assignee: log4j-dev
Depends on:
Reported: 2005-02-23 14:37 UTC by Gon
Modified: 2007-03-23 14:05 UTC (History)
1 user (show)


Note You need to log in before you can comment on or make changes to this bug.
Description Gon 2005-02-23 14:37:29 UTC
I am working with log4j version 1.2.9.

I am trying to subclass a logger with my own logger (because I want it
to accept varargs style logging, for example debug("hello",new
Integer(1), "Hello"); )

I managed to get it working but, and this is weird, only when
configuring the logger by log4j.properties.

I'm using the following configuration:
log4j.rootLogger=DEBUG, A1
log4j.appender.A1.layout.ConversionPattern=%5p [%t] %c - %m%n

With this, it works greate.

However, if I try to use the following xml configuration (log4j.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
<appender name="ConsoleAppender"
  <layout class="org.apache.log4j.PatternLayout">
       <param name= "ConversionPattern" value= "%5p [%t] (%F:%L) - %m%n"/>
<logger name="some.cat">

      <level value="debug"/>
      <appender-ref ref="ConsoleAppender"/>
<categoryFactory class="logging.VarArgsLoggerFactory"/>

I get a "ClassCastException" error, due to the erroneous processing of
the "categoryFactory" element.

I was debugging the DOMConfigurator class and I found out that, at
line parseCategoryFactory the class is perfectly instanteated but
nothing is done with it !
On the other hand, on PropertyConfigurator I found out that, on line
459 there is the following statement:
PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");

which I thing that updates the configuration.

In resume, I think that DOMConfigurator must update the cat variable
in the parseCategoryFactory method (as it does for the other
configuration elements).
Is this resolved in the latest version of Log4j ?

Please help me, I really need to get this working.

Plus, can anyone provide me an actual log4j.dtd?

Thank you very much,
Comment 1 Jacob Kjome 2005-02-23 18:46:50 UTC
If you move to Log4j 1.3, this is handled natively.  Actually, you can do this
with the more generic UGLI interfaces as well.  I wouldn't subclass, and if you
do, you should wrap instead.  See Log4j docs for info.

Log4j-1.2.x is almost surely not going to have another release, so your best bet
is to move to 1.3 ASAP if 1.2.9 isn't working for you.  Oh, and DOMConfigurator
is deprecated in 1.3 in favor of JoranConfigurator, which is much more flexible.
 I'm going to close this as WontFix.  If you find you still need to wrap Log4j
loggers when using 1.3 and this still doesn't work for you with
JoranConfigurator, then please reopen this bug and move the version to 1.3alpha
(I moved it back to 1.2 since the bug is reported on 1.2.9).

Comment 2 Gon 2005-02-23 22:02:08 UTC
I am actually using log4j 1.3.
My issue with subclassing is to avoid the parameter handling as in
log.debug("hello" + object1 + " I am  " + object2); I am subclassing a logger
with VarArgs support so I can write the above as:
log.debug("hello %s I am %s",object1,object2). So this way Java won't build the
strings unless it is really necessary.
I am aware of Joran configurator but it does not handle the loggerFactory and
thus I get a ClassCastException runtime error.

The subclassing examples on log4j has the good.cat that calls one attention to
the categoryfactory=XXXXXXX configuration that is not present at bad.cat file. 

So the final question is: how can I subclass without getting a ClassCastException..

Thank you for your quick reply.
Comment 3 Jacob Kjome 2005-02-24 18:15:50 UTC
Hmm.. you reported Log4j-1.2.9 in your initial report.  Was that a typo?

In any case, you say you are using Log4j-1.3alpha now.  If that's the case, then
you don't need to wrap Log4j loggers to get the behavior you want.  See...


And note that Log4j-1.3 directly implements UGLI.  You can also compile against
any individual UGLI jar such as the ugli-nop.jar.  This makes you jar
dependencies very small and lets the end user decide what kind of logging they want.

Comment 4 Elias Ross 2007-01-28 02:59:47 UTC
<categoryFactory class="logging.VarArgsLoggerFactory"/>


<loggerFactory class="logging.VarArgsLoggerFactory"/>

is now supported in 1.3 (SVN trunk).  Check the DTD.
Comment 5 Paul Furbacher 2007-03-18 19:56:24 UTC
Based on my own attempts to use <categoryFactory> element in log4j-1.2.13, I
find that this bug in DOMConfigurator is *not* fixed.  The same symptoms prevail
as shown by the original poster: i.e., a ClassCastException.  (I could find no
test case for either categoryFactory or loggerFactory configuration in
log4j.xml, so I don't know how anyone could claim it is fixed.)

It would be nice if it could get fixed for log4j-1.2.15.  

The following diff shows how to fix this problem.

--- src/java/org/apache/log4j/xml/DOMConfigurator.java  2007-02-23 12:48:53.408
-0500     511036
+++ src/java/org/apache/log4j/xml/DOMConfigurator.java  2007-03-18 22:25:07.597
@@ -109,6 +109,9 @@
   Properties props;
   LoggerRepository repository;
+  protected LoggerFactory catFactory = null;
      No argument constructor.
@@ -258,7 +261,10 @@
 	  } else if(tagName.equals(LOGGER_REF)) {
 	    String loggerName = currentElement.getAttribute(REF_ATTR);	    
-	    Logger logger = repository.getLogger(loggerName);
+      Logger logger =
+          (catFactory == null)
+          ? repository.getLogger(loggerName)
+          : repository.getLogger(loggerName, catFactory);
 	  } else if(tagName.equals(ROOT_REF)) {
 	    Logger root = repository.getRootLogger();
@@ -317,7 +323,9 @@
     if(EMPTY_STR.equals(className)) {
       LogLog.debug("Retreiving an instance of org.apache.log4j.Logger.");
-      cat = repository.getLogger(catName);
+      cat = (catFactory == null )
+          ? repository.getLogger(catName)
+          : repository.getLogger(catName, catFactory);
     else {
       LogLog.debug("Desired logger sub-class: ["+className+']');
@@ -361,8 +369,8 @@
     else {
       LogLog.debug("Desired category factory: ["+className+']');
-      Object catFactory = OptionConverter.instantiateByClassName(className, 
+      catFactory = (LoggerFactory)OptionConverter.instantiateByClassName(className,
       PropertySetter propSetter = new PropertySetter(catFactory);
Comment 6 Curt Arnold 2007-03-23 14:05:44 UTC
Commited fix and test cases against 1.2 in rev 521903.