Aspect questions?

A

Arved Sandstrom

That's an interesting approach, though not one that I use. I tend to
prefer a single logger per process with an associated level attribute,
and to sprinkle classes with logger calls specifying different levels so
I can vary the logged detail depending on what I need to see. The minimal
level may correspond to nothing more than reporting overall run
statistics. Next level will log method exits and show call arguments plus
return value. The level above that shows method entry and beyond that
anything that might be relevant in the method internals: both of these
are omitted unless the method is complex enough to require them.
[ SNIP ]

I don't see anything you say above as being in conflict with the
"standard" use of individual loggers in Java logging frameworks.

I can only speak for myself, but I hope that pretty much everyone does
what I am about to describe, or at least gets it. When working through a
given method in a given class, you decide that at various points you
have information that should be logged. You also know for each piece of
information what logging level applies: the association of an
appropriate logging level (e.g. DEBUG, INFO, WARN, ERROR, or
equivalents) with corresponding information to be logged is probably the
most important decision that you, the log statement coder, can make.
It's not going to change; it's not supposed to change.

It is entirely appropriate to have two or three log statements one after
another, each at a different level, each with different information.
What a lot of developers do though is squash all that together into one
log statement at one level: they have just defeated the purpose of logging.

The point of having (typically) a logger per class, as Lew indicated, is
to then give you the other piece of the puzzle - fine-grained
configuration. This does exactly what you do with your "process" logger,
and more: from that XML or .properties config file you can easily
control which of your log statements in a given package or class get
logged, by level.

To summarize, the methods in class a.b.c.X get all "logged up", with
statements at various carefully-chosen levels. From the config file we
control for package a.b or a.b.c or even specifically for class a.b.c.X
whether we want to see everything above INFO inclusive, say, or
everything down to DEBUG.

On a sidenote the configuration isn't just deployment time. With Java EE
5 and 6 servers it's generally reasonably straightforward to do a bit of
coding to expose selected logging framework functionality through a JMX
MBean, such as the ability to change levels by logger. I'll add that
log4j does have a DOMConfigurator.configureAndWatch() method that can be
used to load up XML configuration, and have a thread check for config
file changes at intervals; I've seen this approach fail with app server
restarts so I stick to JMX.

AHS
 
A

Arne Vajhøj

Lastly, I don't know about log4j, but I don't think the
java.util.logging package uses threads when logging. Any IO operations
the logger makes will block the calling thread. I've heard this is
undesirable in most cases. So rolling your own framework also gives you
control over threading issues too, which again might be important for
some customers.

I don't think log4j write in a separate thread either.

But I don't think it is necessary.

If the call actually had to block until the data were written
to the rotating plates, then it could be significant.

But on modern OS'es the data will just be copied over to
some system memory where it will be transferred to the RAID
controller memory where it will be transferred to the memory
in the drives before it eventually end up on the plates.

Arne
 
A

Arne Vajhøj

Back when I was playing with applets, I discovered by default that the
jul logger creates a log file in your home directory. (There's a default
logging.properties file created with every Java desktop installation and
that's what it does). With unsigned applets, this means even trying to
instantiate any part of the jul logging system will throw an exception,
because the applet has no permissions for creating files.

There might be ways around that, but it spooked me and I decided that
since I didn't have direct control over a user's system, I couldn't rely
on any defaults in the JRE installation. So I made a shell logging
system that wrapped the jul logger and allowed me control, in case I had
to use something besides jul entirely.

I seem to recall that log4j is a bit more applet friendly than jul.

Note that the applet should send log info back to the site it came
from.

Arne
 
A

Arne Vajhøj

Can you suggest any specific projects/products that you think are
particularly well-written? I had thought of looking at such code before
but I'm not sure I'd necessarily recognize well-written code if I found
it. It might look strange to me but actually be brilliant or viceversa.

Most widely used open source Java server products would be fine.

My immediate ideas would be products like Apache ActiveMQ and
JBoss AS.

Arne
 
N

Novice

Lew said:
Yeah, I figured that out after the fact. You were doing a weird thing
by creating a factory method to call the factory method to create the
logger.


No. The difference is that I put the logger code in each class, and
don't have a centralized factory factory. That's because the logging
framework already provides a factory and a way to configure it, so I
don't try to reinvent that entire mechanism.


It's not irrelevant, depending on what you think is relevant. It
prevents reassignment of the reference, and as a comment lets
maintainers know the intent is to have an immutable reference.

But you are correct that is actually wasn't so necessary here.
Relevant was probably not the right word to use there but it was the
closest I could think of at the time. Some time ago, I saw a post where
someone had a local variable defined as final and someone remarked that
it wasn't necessary or appropriate or whatever to put final on a local
variable. That's all I meant to say. I'm happy to put final on my local
variables or leave it out, whichever is appropriate.
'logger.severe()' right at the point, just before the throw.


Actually, you should indent with spaces not TABs routinely.

Fair enough. I've gone into Eclipse, nosed around until I found where the
tabs are created (in "Formatter") and created a new profile that uses
spaces instead of tabs.
And strip
out the superfluous comments in your own code, too - that is, if
they're actually superfluous.
When I write code, I typically write a comment first to express the
intent of what I want the next line or lines to do. Then I write the code
and leave the comment there due to the brainwashing I got in my early
days about always commenting everything. I try very hard to choose very
clear names for things like variables, methods, and classes and I'd like
to think the code is nearly self-explanatory most of the time without the
need for comments. I'm sometimes tempted to erase all or most of the
comments but then it occurs to me that what is obvious to me may not be
so obvious to a total beginner and maybe it's a good thing to leave the
comments there for their sake. In short, I agree that the comments in the
method I posted don't really need to be there for my sake but, as long as
I keep them accurate - and I usually do - they might conceivably help
someone else.

I didn't stop there. I did say why.
I hadn't got that far yet ;-)
You don't need that. You just call 'Logger.getLogger()'. The utility
class is a whole lot of weird complication that you don't need.


Yes, that is correct.
I gave your suggestion a try in my sandbox, where I'm playing with
Aspects. I wrote this little class:

=========================================================
package test;

import java.util.logging.Level;
import java.util.logging.Logger;

public class TestLogging {

public static void main(String[] args) {

@SuppressWarnings("unused")
TestLogging test = new TestLogging();
}

public TestLogging() {

Logger logger = Logger.getLogger("test");
logger.logp(Level.INFO, "myClass", "myMethod", "Monday");
logger.logp(Level.INFO, "myClass", "myMethod", "Tuesday");
logger.logp(Level.INFO, "myClass", "myMethod", "Wednesday");
logger.logp(Level.INFO, "myClass", "myMethod", "Thursday");
logger.logp(Level.INFO, "myClass", "myMethod", "Friday");
logger.logp(Level.INFO, "myClass", "myMethod", "Saturday");
logger.logp(Level.INFO, "myClass", "myMethod", "Sunday");
}
}
==============================================================

The code ran fine and the logging statements all appear nicely in red on
my console. So far, so good.

But I'd like them to appear in a log file somewhere, too. My
logging.properties has the following lines:

handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

By my reckoning, that should ensure that I'm also getting a log file and,
since I'm running on Windows XP, I should be able to find it at C:
\Documents and Settings\[Windows ID]\javaX.log. Well, I've got a
java0.log through java4.log in that directory but none of them contain my
logging statements.

The only other place I can find to look, suggested by this site -
http://docs.oracle.com/javase/1.5.0/docs/guide/deployment/deployment-
guide/tracing_logging.html - translates to C:\Documents and Settings
\[Windows ID]\Application Data\Sun\Java\Deployment\log. There's exactly
one file in that directory and it is a Java log with the ungainly name of
plugin5581819941091650582.log but it contains only this:

<?xml version="1.0" encoding="windows-1252" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
</log>

I'm not sure where else to look so I'm going back to the docs to see what
other clues I can find. I suspect that the indirection involved in trying
to find the log files was another factor in which I decided to create the
loggers the way I did....

The logged files simply aren't much use if you can't find them.
No. I never said nor implied that you should have one logging file per
class. That one's on you, brother.
Okay. Your phrasing was a bit confusing. I read it as "You don't create
multiple files, (you create) one per class." Apparently that's not what
you mean after all. Sorry.
Yes, but why are you arguing a point not in dispute?
Because your phrasing seemed to imply that I DID want one log per class.
How you do go on.

No one is suggesting anything like that scenario. so cool your jets,
Cadet!

Wow.
Sorry. I was confused by what you seemed to imply.
A configuration file is a file that contains configuration
information.
I'd guessed that much ;-) I'm trying to figure out what they contain,
where I put them, etc. Reading ahead, you're about to explain that....
As far as what you don't remember, if you follow the link from the API
docs for java.util.logging:
<http://docs.oracle.com/javase/7/docs/api/java/util/logging/package-sum
mary.html>

You come across a recommendation to read the introduction to Java
logging, which I sure hope you followed:
"Related Documentation
For an overview of control flow, please refer to the Java Logging
Overview." which links you to
<http://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview
.html> wherein you would have read, had you read it,
<http://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview
.html#a1.15> "The APIs are structured so that an initial set of
configuration information is read as properties from a configuration
file."

As for the tutorials, you have
<http://lmgtfy.com/?q=Java+logging+tutorial>
which among other links will find you
<http://forward.com.au/javaProgramming/javaGuiTips/javaLogging.html>
that covers a little about the "logging.properties" file.
Actually, I have been in all of those documents in the last several hours
as I've been trying to puzzle out the right way to do logging. I'd seen
all of them before at some point, but it was a fair while ago. Back then,
I played with logging and came up with the logging code I posted (more
or less). I truly don't remember how I got to that code though. At a
guess, I didn't want the logs to go where the logging properties file
wanted to put it and wanted it in a directory within each project so that
it was more convenient, rather than putting all logs in the same
directory.

As for the term "configuration file" I didn't realize you meant
"logging.properties". That was my confusion there; I don't recall hearing
that called a configuration file before and thought you were talking
about something completely new and outside my experience.
GIYF, dude.
GIYF??


Abusing
not deliberately, I assure you.
Huh. That's the configuration file, dude.
Now the penny drops....
effect that I wanted and I created my own variant on the XMLFormatter
that is only very slightly different. Aside from that, I'm using the
vanilla logging classes. I'm not sure how that constitutes
reinventing the framework. But, as I said, I'm going to review the
logging classes now and see if I'm overcomplicating the creation of
the logger as you say. Perhaps I am....

The properties file specifies the log file, the log level (by type if
you so choose), the output format, whether you report the class and
method being logged - all the things you did manually in your utility
class.
And when I said you should know both ju.logging and log4j, somehow
you inferred that to mean that you should use both in the same
program. Such leaps you make! Settle back and stick with inferences
that actually follow from what I say.
Well, here's the exact quote:

"Use log4j or java.util.logging (OR BOTH)". [emphasis added]

Not in the same code! Yeesh.

...
As I've said, I'm a one man Java shop in a town that doesn't seem to
do much Java. I don't work in a professional Java shop so I have no
professional Java code to look at or peers to learn from. So I'm
floundering. That's why this newsgroup is important to me. I _AM_
trying to get better at this....

Of course, hence the detailed feedback.

Which I appreciate, even if I seem a bit grumpy or frustrated at times.

But I'm still confused about the scope of my logs. According to the
logging overview, I want the argument to Logger.getLogger() to be "A name
for the logger. This should be a dot-separated name and should normally
be based on the package name or class name of the subsystem, such as
java.net or javax.swing."

I expect that they are assuming that each project has a unique package
name. Therefore, if my company is novice.com, then the Foo project will
presumably have a package named com.novice.foo and the Bar project will
have a package named com.novice.bar. Then, the logging for the Foo
project will be based on Logger.getLogger("com.novice.foo"), right? Then
every class within the Foo project will have the line:

Logger logger = Logger.getLogger("com.novice.foo");

Have I got this so far?

If so, the next logical step would be to treat all the stuff in the
Common project similarly. If I put all of those classes in package
com.novice.common, then each class would have this:

Logger logger = Logger.getLogger("com.novice.common");

Or would it be better to get a reference to the logger within Foo and
pass that to the classes in the Common project so that they write to the
logger used by the instantiating class from Foo?

Now, as it turns out, I've actually got a bunch of packages in project
Common. I'm separating different kinds of common classes via packages.
I'm not sure now if that is a good idea or a bad one. I've got separate
packages with the Common project for utilities, for classes dealing with
preference handling, for classes that are just simple lookups (including
Enums), classes that create generic panels for GUIs, etc. So maybe I need
to ask first if it is a bad idea to separate my common code into
categories or if it is better to lump it all together into a single
package.

If keeping the separate packages is a good idea, then I need a bit of
guidance on whether there should be a separate logger for each package or
whether I'm better to write all messages from all Common classes to the
same logger, e.g. com.novice.common despite their different packages.

Now, if Project Foo only uses code from one other project, Common, I only
have two logs to worry about, the one that has all the Foo stuff and the
one that has all the Common stuff. That's not too bad. Then again, maybe
it would be better to use Logger.getLogger("com.novice") and write every
message from every class I write to the very same log, regardless of
project. What is the best practice here?

I feel like I'm starting to see what you have in mind but I hope you stay
with me for just a bit longer until we've hashed the last bits out. I
don't want to go off in the wrong direction again so I need your
confirmation that I'm starting to get it now.
 
A

Arne Vajhøj

But I'm still confused about the scope of my logs. According to the
logging overview, I want the argument to Logger.getLogger() to be "A name
for the logger. This should be a dot-separated name and should normally
be based on the package name or class name of the subsystem, such as
java.net or javax.swing."

I expect that they are assuming that each project has a unique package
name. Therefore, if my company is novice.com, then the Foo project will
presumably have a package named com.novice.foo and the Bar project will
have a package named com.novice.bar. Then, the logging for the Foo
project will be based on Logger.getLogger("com.novice.foo"), right? Then
every class within the Foo project will have the line:

Logger logger = Logger.getLogger("com.novice.foo");

Have I got this so far?

If so, the next logical step would be to treat all the stuff in the
Common project similarly. If I put all of those classes in package
com.novice.common, then each class would have this:

Logger logger = Logger.getLogger("com.novice.common");

Or would it be better to get a reference to the logger within Foo and
pass that to the classes in the Common project so that they write to the
logger used by the instantiating class from Foo?

The standard is to use the full (with package) class name as
the name of the logger.

Because logger configuration is applied tree wise, then you can
still configure at package level.

If you used package name as logger name, then you could
not configure by class.

Arne
 
M

markspace

If so, the next logical step would be to treat all the stuff in the
Common project similarly. If I put all of those classes in package
com.novice.common, then each class would have this:

Logger logger = Logger.getLogger("com.novice.common");


Just as an aside, it's more common to use something like

java.util.logging.Logger.getLogger( getClass().getName() );

instead of a string constant. String constants probably won't be
refactored when a class is renamed or moved to another package. The
above needs no refactoring.

Also:

<http://commons.apache.org/logging/guide.html#Developing With JCL>

This section points out that it's more efficient to use "static" for the
logger. In desktop apps, that's what I'm used to seeing. However it
also says that "static" interacts poorly with JEE classloaders, so using
instance variables is the norm in JEE (and w/ Tomcat too).
 
N

Novice

viceversa.

Most widely used open source Java server products would be fine.

My immediate ideas would be products like Apache ActiveMQ and
JBoss AS.

Thanks for the suggestions, Arne. I'll see what I can learn from that
code!
 
N

Novice

markspace said:
I can think of a use case for it though. Let's say you haven't decided
which logging framework to use, or you want to be flexible as to which
one to use. (Different customers of yours prefer different loggers.)

(Not syntax checked or tested.)

abstract class MyLogger {

public static MyLogger getLogger( String name ) {
MyLogger logger = Class.forName(
System.getProperty("me.mystuff.MyLogger.logImpl",
"me.mystuff.MyDefaultLogger" ).newInstance());
return logger;
}

public abstract void logStuff(Object...);
}


So the idea is that you wrap the logging framework in your own, and then
you're free to provide an implementation that matches whatever logging
framework you choose to use in the future. Maybe this is not for
everyone, but I could see its advantages. Some folks might like
java.util.Logger, some folks like log4j. And some might like things
that I don't know about yet.
I wish I could say I was that clever but I'd be lying if I did.

I've simply been doing logging incorrectly. I don't even remember what
thought process got me doing things the way I do in my code. I worked
that technique out a few years ago, then had a gap away from Java for a
while and am finally revisiting a lot of my old code to do things the
proper way. Lew has convinced me it's not the right way to do things. Now
I'm trying to get a clear picture of what I SHOULD be doing so that I can
revise my code....

A couple of other things.

Lew wrote:

public class Foo
{
final Logger logger = getLogger(getClass());
[...]
}

This requires that a logger is instantiated for each object as it is
created. Potentially this is a lot of work, and each logger may not be
used. (Even declaring the logger to be static still requires a logger
per class loaded.)

Whereas this:

...
try {
... some stuff...
} catch (Exception ex) {
getLogger(getClass()).log( ... );
}

creates the logger lazily and therefore doesn't spend any resources if
logging happens to be never required.

Lastly, I don't know about log4j, but I don't think the
java.util.logging package uses threads when logging. Any IO operations
the logger makes will block the calling thread. I've heard this is
undesirable in most cases. So rolling your own framework also gives you
control over threading issues too, which again might be important for
some customers.
 
N

Novice

markspace said:
Just as an aside, it's more common to use something like

java.util.logging.Logger.getLogger( getClass().getName() );
Of course. I was already intending to substitute that once I'm clear on
what my code should be doing. I'd much rather derive the name rather than
hard-code it.
instead of a string constant. String constants probably won't be
refactored when a class is renamed or moved to another package. The
above needs no refactoring.

Also:

<http://commons.apache.org/logging/guide.html#Developing With JCL>

This section points out that it's more efficient to use "static" for the
logger. In desktop apps, that's what I'm used to seeing. However it
also says that "static" interacts poorly with JEE classloaders, so using
instance variables is the norm in JEE (and w/ Tomcat too).
I'm writing more applications/Java Web Start these days than servlets so
maybe I should use 'static' and then remember NOT to use it in
servlets....
 
N

Novice

As soon as a mention of commons logging comes up, I feel bound to
mention SLF4J. :)

For the OP, if you're genuinely researching Java logging, check out
SLF4J (http://www.slf4j.org/). This is a facade for other logging
frameworks, so you'd actually implement using JUL or log4j or logback.

Right now, I'm focusing on trying to use JUL correctly and I'm a little
worried that I'm going to confuse myself by switching horses to a
different logging approach. But it sounds like sfl4j may be the way to go
in the not too distant future.

As it happens, I downloaded a package called DBPool this week and had a
newbie question that involved logging. My question didn't seem to be
covered in the documentation. I used the email link on the web page and
got some assistance from the developer. He mentioned in passing that he
is probably switching to slf4j in his next release. That was the first
time I heard of it but from what you're saying, it may be the way to go
very soon....

By the way, I've skimmed the introduction to slf4j on their website. It
looks pretty good! Maybe I SHOULD switch to that approach!
Note that the same fellow who is responsible for log4j also drives
slf4j and logback.

Also while we are at it, I recommend
http://www.javacodegeeks.com/2011/01/10-tips-proper-application-logging
.html as a good list of tips for application logging.
Interesting article! I'm not finished yet but the 6th of his tips seems
very counter-intuitive. He strongly advocates not including the class
name and method name in the log records. To my way of thinking, those are
among the most essential parts of the message. If I don't know where the
message was written, how am I supposed to find the source code to debug
it?

I really don't see what he's saying. Is he assuming that the class name
and method name will be inferred in some other way anyway so it isn't
necessary to include that in each log message? If so, how will it be
determined? Otherwise, this tip doesn't seem to make any sense.

[ SNIP ]
It's actually common for libraries to use either ju.logging or log4j
without regard for your preference, with the result that both
frameworks wind up in the same program.

Yes. There are a few different situations that arise here. In one
case, the 3rd party library uses the *same* logging framework as you
do. In which case, depending on overall environment and various
classloaders, don't be surprised if your logging configuration also
applies to that 3rd party library. You may start out with an
unexpected spew of log statements in your log files until you finetune
your loggers.

From my standpoint I always see that extra flow of info with
gratitude. I'll usually set first logging configuration to DEBUG for
the packages in 3rd party libraries, just to see what I get. If the
external parties also wrote good logging statements then the result is
a major bonus, to again be filtered and directed as needed.

In the other major case, the 3rd party library uses something
different. Pay attention to that; hunt down its logging configuration
file. You're not just using that library's Java API, you're also using
its ability to log what's happening. Avoid having it be a black box
that you can only debug into with decompiling to try to figure out
what it's doing.
I think in Java those two pretty much have it sewn up.

See above wrt slf4j and logback.

Thanks for another very helpful post, Arved!
 
N

Novice

The standard is to use the full (with package) class name as
the name of the logger.

Because logger configuration is applied tree wise, then you can
still configure at package level.

If you used package name as logger name, then you could
not configure by class.
Okay, fair enough. Hmm, I need to think through the implications of
that....

So, with respect to my common classes, should they all be in one big
package, like com.novice.common? Or is it better to group them on some
basis so that different types of common modules are in their own
packages? If grouping them is a good idea, what's the best way to group
them?

I'm currently grouping mine on a more-or-less functional basis. If the
class is essentially just a table lookup or enum, then it goes in the
com.novice.common.lookups package. If it is a utility, it goes into
com.novice.common.utilities. And so forth.

Also, do you have any idea where to find the log records I am writing
when I use Logger.getLogger("test") in my play code? I've tried the
location stated in logging.properties and I've tried

<User Application Data Folder>\Sun\Java\Deployment\log on Windows

as suggested in
http://docs.oracle.com/javase/1.5.0/docs/guide/deployment/deployment-
guide/tracing_logging.html

but I'm not finding it. There are files there but the days of the week
are NOT in them and that's what I wrote to my logger.

I don't know where else to look.
 
L

Lew

Okay. Your phrasing was a bit confusing. I read it as "You don't create
multiple files, (you create) one per class." Apparently that's not what
you mean after all. Sorry.

The sentence began with "You don't...". I fail to see what can be confusing
there. An appositive phrase doesn't invert the sense of the predicate.

Which leaves the question of how we got the miscommunication in the first
place, when I never suggested such a thing.
Because your phrasing seemed to imply that I DID want one log per class.

Sorry. I was confused by what you seemed to imply.

"Seemed" foists the responsibility off. I didn't do the "seeming".

....
As for the term "configuration file" I didn't realize you meant
"logging.properties". That was my confusion there; I don't recall hearing
that called a configuration file before and thought you were talking
about something completely new and outside my experience.

I used the term in the exact same sense as the logging library documentation
and in computer programming generally.
http://lmgtfy.com/?q=GIYF
....

I expect that they are assuming that each project has a unique package
name. Therefore, if my company is novice.com, then the Foo project will

Huh?

Have you read the Java tutorial?
presumably have a package named com.novice.foo and the Bar project will

Don't presume; design. It is very possible that the "Foo" project will not
have a package 'com.novice.foo', if it has 'com.novice.foo.qux',
'com.novice.foo.bleh' and so on.
have a package named com.novice.bar. Then, the logging for the Foo
project will be based on Logger.getLogger("com.novice.foo"), right? Then
every class within the Foo project will have the line:

Logger logger = Logger.getLogger("com.novice.foo");

No, it won't. First, you have completely ignored that I said "one logger per
class". How did you distort that into "one logger per package"? Second, you
don't design packages for the logger, you design loggers for the packages.
Have I got this so far?

Not yet.
If so, the next logical step would be to treat all the stuff in the
Common project similarly. If I put all of those classes in package
com.novice.common, then each class would have this:

STOP!

I don't know how you make these leaps, and I am defeated as to how to advise
you not to. You go on for paragraphs about bad ideas that were never suggested
to you.
Logger logger = Logger.getLogger("com.novice.common");

Or would it be better to get a reference to the logger within Foo and
pass that to the classes in the Common project so that they write to the
logger used by the instantiating class from Foo?

Once again, I repeat, and you may recall the Javadoc quotes I provided
upthread on this matter, getting a logger with a particular name gets a
reference to that same-named logger. Already. Without additional complication
on your part. It's built in. You don't need to reinvent it. It already
happens. All you have to do is give the same name. You will already have
gotten the reference. You don't have to pass it anywhere. It's already there.
Read the Javadocs. Again. And again. And again. And again. Don't read what
isn't in there - read what it says. It says that if you give the 'getLogger()'
the same name, it will return a reference to the same logger.

Aside from that, I have no idea at all what you intend to say by, "so that
they write to the logger used by the instantiating class from Foo". What
precisely do you mean there?
Now, as it turns out, I've actually got a bunch of packages in project
Common. I'm separating different kinds of common classes via packages.
I'm not sure now if that is a good idea or a bad one. I've got separate

READ THE TUTORIAL!
packages with the Common project for utilities, for classes dealing with
preference handling, for classes that are just simple lookups (including
Enums), classes that create generic panels for GUIs, etc. So maybe I need
to ask first if it is a bad idea to separate my common code into
categories or if it is better to lump it all together into a single
package.

It is better to group types into packages.
If keeping the separate packages is a good idea, then I need a bit of
guidance on whether there should be a separate logger for each package or
whether I'm better to write all messages from all Common classes to the
same logger, e.g. com.novice.common despite their different packages.

Once again, as I stated upthread some time ago and others have reiterated, the
common practice (but by no means the only one) is one logger per class.

Loggers "inherit", so that gives some flexibility in how you do things.
Now, if Project Foo only uses code from one other project, Common, I only
have two logs to worry about, the one that has all the Foo stuff and the
one that has all the Common stuff. That's not too bad. Then again, maybe

What? You should only have one log, unless they use different libraries to log.
it would be better to use Logger.getLogger("com.novice") and write every
message from every class I write to the very same log, regardless of
project. What is the best practice here?

Huh? again.

What you name the logger is not connected to where it logs. Where it logs is
determined by the configuration for that logger. Usually it'll write to the
same log as its parent. The best practice here is to make sense in the first
place. You ask a question about naming a logger, but cast it in turns of where
it logs. Apples and oranges, dude. Naming a logger doesn't change where it
logs. Read the logger documentation, please. All this information is in the
documentation.

The configuration determines where the log goes. No changes to logger names
are needed, just change the configuration file and restart.

We're starting to make the same points over and over again. It's frustrating
to provide you an answer and have you come back with the same question. Please
assimilate the answers already given.

To summarize the repeated points here:

- Configuration files usually suffice to configure logging. You rarely need to
programmatically configure logging, and should resist doing so. Otherwise you
defeat the point of changing logging strategy without having to rebuild.

- The logger name determines which logger instance you get. NOT, and I repeat,
*NOT* where it logs.

- Conventionally, and usually most usefully, loggers are named for the class
in which they are used. So the logger for 'com.lewscanon.example.Foo' would
come via 'getLogger(com.lewscanon.example.Foo.class.getName())'.

and emergingly,

- Packages are to organize your program irrespective of logging strategy.

Some of this is material in the basic tutorial, particular the info about
packages, and should be mastered first before, say, learning how to code a
for-each loop.
I feel like I'm starting to see what you have in mind but I hope you stay
with me for just a bit longer until we've hashed the last bits out. I
don't want to go off in the wrong direction again so I need your
confirmation that I'm starting to get it now.

Your commitment is duly noted and quite laudable.

But "starting" is still a long way from "hash ... the last bits out". So I
hope your patience is up to the task. You lack certain Java fundamentals.
 
L

Lew

Just as an aside, it's more common to use something like

java.util.logging.Logger.getLogger( getClass().getName() );

instead of a string constant. String constants probably won't be refactored
when a class is renamed or moved to another package. The above needs no
refactoring.

Also:

<http://commons.apache.org/logging/guide.html#Developing With JCL>

This section points out that it's more efficient to use "static" for the
logger. In desktop apps, that's what I'm used to seeing. However it also says
that "static" interacts poorly with JEE classloaders, so using instance
variables is the norm in JEE (and w/ Tomcat too).

"Efficient"? Really? Sounds like premature optimization, and it's the wrong
criterion down the line for loggers. *How* much more "efficient", and at what
cost, is the 'static' logger?

I prefer instance members for loggers. Greater flexibility and no measurable
loss in "efficiency", whatever that is. Actually, I find instance member
loggers more efficient, for the metric of efficiency that I care about.
(Robustness in the face of refactoring, per your suggestion, which wouldn't
compile if the logger were static.)

Aside: log4j lets you skip the 'getName()' call and just specify the class as
an argument, the name-by-class pattern is so widespread.
 
L

Lew

Novice said:
Interesting article! I'm not finished yet but the 6th of his tips seems
very counter-intuitive. He strongly advocates not including the class
name and method name in the log records. To my way of thinking, those are
among the most essential parts of the message. If I don't know where the
message was written, how am I supposed to find the source code to debug
it?

By the content of the message, duh.

The problem with using the logger to reflectively obtain the class and method
name is that the documentation claims it is a horrid performance penalty, as
you would know if you read the logger documentation.
I really don't see what he's saying. Is he assuming that the class name
and method name will be inferred in some other way anyway so it isn't

No, he's recommending that if you need that information that you include it in
your message explicitly, not by inference.
necessary to include that in each log message? If so, how will it be
determined? Otherwise, this tip doesn't seem to make any sense.

There's that word "seem" again. You need to stop using it.

You know damn well that the tip makes sense. You just don't know how yet.

"Seems" is putting a wall between you and comprehension.

As far as the cost of using the logger to elicit class and method information,
that probably won't matter as much as the documentation claims. At level
WARN[ING] and above, performance is probably not an issue, and below that you
usually have logging disabled, and performance again is not an issue. When you
do have DEBUG [FINE] enabled, you probably aren't examining performance and
again it doesn't matter. So I tend to go ahead and use the logger to show
class and method data.

Since you can change this by altering the configuration file without
rebuilding the app, it's a non-issue. You just change the logging output as
you need when you need to.
 
A

Arne Vajhøj

Okay, fair enough. Hmm, I need to think through the implications of
that....

So, with respect to my common classes, should they all be in one big
package, like com.novice.common? Or is it better to group them on some
basis so that different types of common modules are in their own
packages? If grouping them is a good idea, what's the best way to group
them?

I'm currently grouping mine on a more-or-less functional basis. If the
class is essentially just a table lookup or enum, then it goes in the
com.novice.common.lookups package. If it is a utility, it goes into
com.novice.common.utilities. And so forth.

That is general question not specific to logging or AOP.

You need a good structure of your classes and source code.

A key factor in the decision between com.novice.common and
com.novice.common.xxxx must be the number of classes.

Do you have so many classes that it makes sense to split up?
Also, do you have any idea where to find the log records I am writing
when I use Logger.getLogger("test") in my play code? I've tried the
location stated in logging.properties and I've tried

<User Application Data Folder>\Sun\Java\Deployment\log on Windows

as suggested in
http://docs.oracle.com/javase/1.5.0/docs/guide/deployment/deployment-
guide/tracing_logging.html

but I'm not finding it. There are files there but the days of the week
are NOT in them and that's what I wrote to my logger.

It should write to the file specified in the properties file.

May we see that?

Arne
 
A

Arne Vajhøj

Just as an aside, it's more common to use something like

java.util.logging.Logger.getLogger( getClass().getName() );

instead of a string constant. String constants probably won't be
refactored when a class is renamed or moved to another package. The
above needs no refactoring.

Also:

<http://commons.apache.org/logging/guide.html#Developing With JCL>

This section points out that it's more efficient to use "static" for the
logger. In desktop apps, that's what I'm used to seeing. However it also
says that "static" interacts poorly with JEE classloaders, so using
instance variables is the norm in JEE (and w/ Tomcat too).

What does "interacts poorly with JEE classloaders" mean??

Arne
 
A

Arne Vajhøj

"Efficient"? Really? Sounds like premature optimization, and it's the
wrong criterion down the line for loggers. *How* much more "efficient",
and at what cost, is the 'static' logger?

Note that there is just one logger on both cases.

The difference is just whether to have multiple instance refs
to it or a single class ref.

I can not imagine the performance difference between those
being noticeable.
I prefer instance members for loggers. Greater flexibility and no
measurable loss in "efficiency", whatever that is. Actually, I find
instance member loggers more efficient, for the metric of efficiency
that I care about. (Robustness in the face of refactoring, per your
suggestion, which wouldn't compile if the logger were static.)

getLogger(getClass()) does not compile with static but
getLogger(Xxxx.class) does and will be refactored, so that
is not a big difference either.

Arne
 
M

Martin Gregorie

So, with respect to my common classes, should they all be in one big
package, like com.novice.common? Or is it better to group them on some
basis so that different types of common modules are in their own
packages? If grouping them is a good idea, what's the best way to group
them?
I'd say generally yes, unless you see a definite reason to put another
(set of) class(es) in a separate package. Example:

My common set forms the org.gregorie.environ package because I regard
these as setting an environment for the stuff I write. However, I also do
a bit of image manipulation and found I was writing repetitive common
code in this area, so that got refactored as classes in the
org.gregorie.image package. And so forth....

Any time you find this approach puts a class where you don't expect to
find it, consider changing your package structure. Its helpful if your
'common' package only contains classes that are likely to be useful for
any program you write (e.g logging and command line parsing) and that
your other packages contain classes that are often used together.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top