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.