logging-log4j-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jacob Kjome <h...@visi.com>
Subject Re: Multiple Projects Using Same Logger
Date Sun, 22 May 2005 18:23:04 GMT
At 09:25 PM 5/21/2005 +0000, you wrote:
 >Jacob, thank you for the response.  Your prolificacy as evinced by the
 >archives is borne out :-)
 >>classes in jars that are put in WEB-INF/lib are run in exactly the same
 >>classloader as those in WEB-INF/classes. You need not do all the checking
 >>of appenders and such.  In fact, you are probably making bad assumptions on
 >>behavior which is why you only ever see the System.out message.  Simply
 >>logger.info("log message");
 >I've confirmed that this 'auto discovery and configuration' works.
 >However, from my reading of the "short" version of the online manual, which
 >states that "Under certain well-defined circumstances however, the static
 >inializer of the Logger class will attempt to automatically configure
 >log4j", but which subsequently severally exemplifies explicitly indicating

Zowie, that's quite a string of words.  I have no idea what it means????

 >the log4j configuration file, I came away with the idea that explicitly
 >indicating the configuration file is preferable.  Let's assume I prefer
 >explicit indication.

I'll have to trust you because of the confusion noted above, but are you 
saying that autoconfiguration works, but your explicit configuration 
doesn't?   In that case, I'd be a bit wary that you are actually 
configuring things properly in explicit configuration.  You do realize that 
autoconfiguration is probably happening anyway.  This is because the static 
initializer will come into play before you config servlet does.  And the 
fact that you have log4j.properties in the classpath (WEB-INF/classes) 
means that autoconfiguration will find the file.  If you insist on explicit 
configuration, then I would recommend you put log4j.properties somewhere 
other than the classpath, such as under WEB-INF, but not 
/classes.  However, this also presents a dilemma, because there may exist a 
Log4j config file somewhere in a higher classloader.  To shortcircuit that, 
I recommend putting a minimal log4j.xml file in WEB-INF/classes that sets 
the root logger to OFF or something like that.  Then, if there is any 
logging happening, you can attribute it purely to the explicit configuration.

 >>No need to have the extra logMessage() method either.  You are hardcoding
 >>Level.INFO, so why not just use logger.info() directly in getBar()?
 >Perhaps, but this shouldn't change working semantics, no?

No, but as written, the code is completely unnecessary, unless you plan to 
do something other than simply log a message in there.

 >>If you see no output from this, then you haven't configured things
 >I do see output--WEB-INF/classes use the logger; WEB-INF/lib doesn't.  I'm
 >trying to discover where I've erred.

Ok, here's the thing.  I hinted at it before, but did not spell it out.  I 
told that "you are probably making bad assumptions on
behavior which is why you only ever see the System.out message".  Allow me 
be more explicit...

 >if ( logger != null && logger.getAllAppenders().hasMoreElements()

1.  You define the logger above.  It won't be null.  The check is 
unnecessary, but causes no harm.  So far so good

2.  You attempt to get the appenders on the current logger and assume that 
hasMoreElements() will tell you if there is an appender defined for that 
logger.  However, I believe this assumption is incorrect.  Inherited 
appenders won't show themselves here.  You added an appender to the root 
logger.  I would hasten to bet that 
getRootLogger.getAllAppenders.hasMoreElements() would return 
true.  However, as no appenders were explicitly added to the current 
logger, hasMoreElements() will return false on the current logger (someone 
please correct me if I'm wrong here).

Again, you over engineered and it bit you.  Had you started simple, you 
would have realized the source of failure once you added this more 
complicated behavior after first seeing the simple behavior work.  That's 
what I mean by KISS.

I just re-read your original message and saw noticed when you said "Now, I 
want to use this already-initialized logger".  Are you under the impression 
that loggers are initialized individually?   When you perform 
configuration, you are configuring the behavior of a "logger 
repository".  The loggers that are mentioned in your config file don't 
necessarily have to exist.  It just that, if they do, they will behave as 
you configured them.  They will only exist upon first use of the logger.  I 
wouldn't call that "initialization" in the same way as the "logger 
repository" is initialized, though.  Keep in mind, loggers have names that 
you assign.  The most common way to name them is based on the package 
hierarchy, which makes it easy to take advantage of logger 
inheritance.  However, this is only a naming convention.  You could define 
a logger in two separate classes, both named "foo" and both would point to 
the same logger instance (as long as they are in the same logger repository).

 >>BTW, are you doing anything special in your InitServlet?  If not, just let
 >>autoconfiguration work for you.  It will find log4j.properties and perform
 >>configuration in a static initializer by default.  No need to do this
 >>manually unless you are doing something special.  You are really over
 >>engineering this.  KISS.
 >No, nothing special in the init servlet but, again, let's say I prefer
 >explicitly indicating the config file to use.  Imay need this dynamic
 >ability later, and removing it is as simple as a web.xml edit.
 >The reason I first call logMessage() is so that it is the one "gateway" to
 >logging (I would, of course, arrange for calls to it not to use the
 >log4j-specific "Level" parameter).  Also, remember that Bar is a separate
 >"library", and I don't want its logs going to log4j when not used in a
 >webapp.  Hence the check for configuredness, etc.

It is difficult to check for Log4j configuredness, at least under 
Log4j-1.2.x.  However, there is some code out there that can help...

See the isConfigured() method at

 >  Lastly, I don't have my
 >source files explicitly sprinkled with logging calls--calls to logging are
 >woven in by AspectJ after the fact; again, AFAICT, this shouldn't change

No, this should not matter in the least.

 >I would like to KISS; but the S is relative :-)

Sure, but I think starting with logger.info() is pretty obviously more 
simple than what you are trying to do.  The point is, start simple.  Add 
complexity as needed.  If you start complex and things don't work, how can 
you pinpoint the cause of the failure?

 >So, in summary, I'm glad "autoconfigure" works, and it's a starting point
 >for me to get to where I want to go.  But I'm still unclear why the setup I
 >described below doesn't work.  I'd be grateful for any insight.

If the only difference between the "working" version of your setup and the 
non-working version is the use of autoconfiguration or not with absolutely 
everything else exactly the same, then I would tend to suspect your 
explicit configuration.


 >> >I want its components, packed in separate jars, to use the same
 >> >if possible.  My configuration is shown below:
 >> >
 >> >j2ee web app
 >> >=======
 >> >    webroot/
 >> >        WEB-INF/
 >> >            classes/
 >> >                log4jInitServlet (uses log4j props file)
 >> >                log4j.properties
 >> >                com.foo/ (classes in this package use logger)
 >> >
 >> >So far so good.  I'm able to initialize a logger, and to log from any of
 >> >classes in "classes/".
 >> >
 >> >Now, I want to use this already-initialized logger to log from classes
 >> >deployed in jar files in WEB-INF/lib/ .  Is this possible?  Thus far my
 >> >attempts have been unsuccessful.
 >> >
 >> >For example, I have a separate java project, whose classes reside in
 >> >"com.bar", and which have been jar-ed and placed in WEB-INF/lib.  One of
 >> >those classes is something like this:
 >> >
 >> >package com.bar;
 >> >
 >> >import org.apache.log4j.*;
 >> >
 >> >class Bar {
 >> >    static Logger logger = Logger.getLogger(Bar.class.getName());
 >> >
 >> >    public void getBar() {
 >> >        logMessage( "called getBar", Level.INFO);
 >> >    }
 >> >
 >> >    private void logMessage(String msg, Level lvl) {
 >> >        if ( logger != null && logger.getAllAppenders().hasMoreElements()
 >> >            logger.log(lvl, msg);
 >> >        else
 >> >            System.out.println("sysout:" + msg + " : " + lvl.toString());
 >> >    }
 >> >}
 >> >
 >> >The idea is that Bar provides some functionality to the webapp, and I
 >> >calls to it logged.  Again, though, I'd like Bar's logging to use the
 >> >logger(s) already-initialised by the webapp.  My props file is as below:
 >> >
 >> >log4j.rootLogger=ERROR, A1
 >> >log4j.appender.A1=org.apache.log4j.ConsoleAppender
 >> >log4j.appender.A1.layout=org.apache.log4j.PatternLayout
 >> >
 >> ># Set levels
 >> >log4j.logger.com.foo=INFO
 >> >log4j.logger.com.bar=DEBUG
 >> >
 >> >However, all log output from bar says "sysout", meaning it isn't using
 >> >logger.
 >Express yourself instantly with MSN Messenger! Download today - it's FREE!
 >To unsubscribe, e-mail: log4j-user-unsubscribe@logging.apache.org
 >For additional commands, e-mail: log4j-user-help@logging.apache.org

To unsubscribe, e-mail: log4j-user-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-user-help@logging.apache.org

View raw message