Hello. 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.debug=true log4j.loggerFactory=logging.VarArgsLoggerFactory log4j.rootLogger=DEBUG, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout 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/" debug="true"> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name= "ConversionPattern" value= "%5p [%t] (%F:%L) - %m%n"/> </layout> </appender> <logger name="some.cat"> <level value="debug"/> <appender-ref ref="ConsoleAppender"/> </logger> <categoryFactory class="logging.VarArgsLoggerFactory"/> </log4j:configuration> 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,
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). Jake
Hello. 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.
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... http://logging.apache.org/log4j/docs/ugli.html 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. Jake
<categoryFactory class="logging.VarArgsLoggerFactory"/> and <loggerFactory class="logging.VarArgsLoggerFactory"/> is now supported in 1.3 (SVN trunk). Check the DTD.
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 -0500 @@ -109,6 +109,9 @@ Properties props; LoggerRepository repository; + + protected LoggerFactory catFactory = null; + /** No argument constructor. */ @@ -258,7 +261,10 @@ eh.setBackupAppender(findAppenderByReference(currentElement)); } 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); eh.setLogger(logger); } 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, - LoggerFactory.class, + catFactory = (LoggerFactory)OptionConverter.instantiateByClassName(className, + LoggerFactory.class, null); PropertySetter propSetter = new PropertySetter(catFactory);
Commited fix and test cases against 1.2 in rev 521903.