Question about loggers

N

Novice

I'm working my way through Stephen Stelting's book Robust Java and have
some questions about the use of the Logging API (java.util.logging) in
Chapter 5.

My impression from the "Aspect Questions" thread was that the "best
practices" approach to logging was to use named loggers, where, in essence,
each method that needs to write to the log creates a named logger via

Logger logger = Logger.getLogger(getClass().getName());

and then writes to the log.

Did I get that right? Stelting mentions anonymous loggers and the global
logger starting on page 71.I see from the API (and by actually trying it in
the sample program below) that the global logger is no longer a recommended
technique but are there any common circumstances where a professional
program would use anonymous loggers? Or are they more a case of something
that might be used in a "sandbox" type program to try something out?

Also, Stelting mentions that you can use the LogManager to "cache Logger
objects for repeat use". What circumstances would justify using LogManager?
I was under the impression that simply doing Logger.getLogger() was
perfectly adequate for a professional quality program. Why would LogManager
be any better than simply making the logger a class variable?

I tried a little sample program that combined LogManager, an anonymous
logger and the global logger and came up with this:

================================================================
package sandbox;

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

public class LoggingTest {

public static void main(String[] args) {
LoggingTest test = new LoggingTest();
}

public LoggingTest() {

Logger logger = Logger.getLogger(getClass().getName());
logger.log(Level.INFO, "Starting the constructor");
System.out.println("1+1=" + (1+1));
calculation2();
calculation3();
LogManager logManager = LogManager.getLogManager();
Logger logger2 = Logger.getLogger(getClass().getName() + ".foo");
logManager.addLogger(logger2);
calculation4();
}

private static void calculation2() {

Logger anonymousLogger = Logger.getAnonymousLogger();
anonymousLogger.log(Level.INFO, "Starting the calculation2() method");
System.out.println("2+2=" + (2+2));
}

private static void calculation3() {

@SuppressWarnings("deprecation")
Logger globalLogger = Logger.global;
globalLogger.log(Level.INFO, "Starting the calculation3() method");
System.out.println("3+3=" + (3+3));
}

private void calculation4() {

LogManager logManager = LogManager.getLogManager();
Logger logger = logManager.getLogger(getClass().getName() + ".foo");
logger.log(Level.INFO, "Starting the calculation4() method");
System.out.println("4+4=" + (4+4));
}
}

================================================================

The log records looked like this:

Date/Time
(YYYY-MM-DD-HH:MM:SS) Sequence Logger Level Class Method Thread
Programmer Message Exception Message Exception Class Exception
Method Exception Line
2012-03-07-16:27:52 0 sandbox.LoggingTest INFO sandbox.LoggingTest
<init> 10 Starting the constructor N/A
2012-03-07-16:27:52 1 INFO sandbox.LoggingTest calculation2
10 Starting the calculation2() method N/A
2012-03-07-16:27:52 2 global INFO sandbox.LoggingTest
calculation3 10 Starting the calculation3() method N/A
2012-03-07-16:27:52 3 sandbox.LoggingTest.foo INFO
sandbox.LoggingTest calculation4 10 Starting the calculation4()
method N/A


Then, I wrote a version using a named logger and a single class variable
and the whole thing looks a lot simpler and cleaner:

====================================================================
package sandbox;

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

public class LoggingTest2 {

Logger logger = null;

public static void main(String[] args) {

LoggingTest2 test = new LoggingTest2();
}

public LoggingTest2() {

this.logger = Logger.getLogger(getClass().getName());
this.logger.log(Level.INFO, "Starting the constructor");
System.out.println("1+1=" + (1+1));
calculation2();
calculation3();
calculation4();
}

private void calculation2() {

this.logger.log(Level.INFO, "Starting the calculation2() method");
System.out.println("2+2=" + (2+2));
}

private void calculation3() {

this.logger.log(Level.INFO, "Starting the calculation3() method");
System.out.println("3+3=" + (3+3));
}

private void calculation4() {

this.logger.log(Level.INFO, "Starting the calculation4() method");
System.out.println("4+4=" + (4+4));
}

}
====================================================================

The log records from that look very similar except that the logger name is
always "sandbox.LoggingTest2":

Date/Time
(YYYY-MM-DD-HH:MM:SS) Sequence Logger Level Class Method Thread
Programmer Message Exception Message Exception Class Exception
Method Exception Line
2012-03-07-16:31:13 0 sandbox.LoggingTest2 INFO sandbox.LoggingTest2
<init> 10 Starting the constructor N/A
2012-03-07-16:31:13 1 sandbox.LoggingTest2 INFO sandbox.LoggingTest2
calculation2 10 Starting the calculation2() method N/A
2012-03-07-16:31:13 2 sandbox.LoggingTest2 INFO sandbox.LoggingTest2
calculation3 10 Starting the calculation3() method N/A
2012-03-07-16:31:13 3 sandbox.LoggingTest2 INFO sandbox.LoggingTest2
calculation4 10 Starting the calculation4() method N/A

For my money, my way is at least as good as Stelting's way and considerably
more concise. The only obvious negative to my approach was the class
variable named 'logger'. I know that class variables are something we want
to avoid whenever we can. But just how bad is it for me to create a single
logger as a class variable? Wouldn't I even be helping my performance to
have the logger be a class variable, especially as the number of methods
that were logging increased? After all, I'd only be creating one logger per
class rather than one for each method that was logging.

I'm worried that I'm fooling myself here and missing some big objection to
doing logging the way LoggingTest2 does it. After all, Stelting has
presumably been writing error handling code correctly for years while I
have only been doing it for days. But I'm not seeing any obvious problems
to my approach, which is essentially the same as what everyone recommended
in the other thread except that I've made the logger a class variable.

Can someone enlighten me? I'm leaning towards implementing either the
technique shown in LoggingTest2 or, if the class variable really is a very
bad idea, using Logger.getLogger() locally in each method to get the
logger.
 
A

Arne Vajhøj

I'm working my way through Stephen Stelting's book Robust Java and have
some questions about the use of the Logging API (java.util.logging) in
Chapter 5.

My impression from the "Aspect Questions" thread was that the "best
practices" approach to logging was to use named loggers, where, in essence,
each method that needs to write to the log creates a named logger via

Logger logger = Logger.getLogger(getClass().getName());

and then writes to the log.

Did I get that right? Stelting mentions anonymous loggers and the global
logger starting on page 71.I see from the API (and by actually trying it in
the sample program below) that the global logger is no longer a recommended
technique but are there any common circumstances where a professional
program would use anonymous loggers? Or are they more a case of something
that might be used in a "sandbox" type program to try something out?

I can not see why saving to type something that give the class name
should be smart even for small things.
Also, Stelting mentions that you can use the LogManager to "cache Logger
objects for repeat use". What circumstances would justify using LogManager?
I was under the impression that simply doing Logger.getLogger() was
perfectly adequate for a professional quality program. Why would LogManager
be any better than simply making the logger a class variable?

Loggers are cached by default.

I have only used LogManager when I wanted to work
with the config.

Arne
 
M

markspace

My impression from the "Aspect Questions" thread was that the "best
practices" approach to logging was to use named loggers, where, in essence,
each method that needs to write to the log creates a named logger via

Logger logger = Logger.getLogger(getClass().getName());


I could see an app that was divided into functional parts, like maybe
"DATABASE" and "GUI", etc. where the logging was specified to use those
names:

Logger log = Logger.getLogger( "GUI" );

But while I could see this, I've never actually heard of anyone
specifying it. Loggers by class name is all I've ever seen.
Also, Stelting mentions that you can use the LogManager to "cache Logger
objects for repeat use". What circumstances would justify using LogManager?
I was under the impression that simply doing Logger.getLogger() was
perfectly adequate for a professional quality program. Why would LogManager
be any better than simply making the logger a class variable?


I think I've done this, exactly once in my life:

public class MyLogger extends Logger {
...
}

....
MyLogger log = new MyLogger();
LogManager.getLogManager().addLogger( log );

If you go through the Logger.getLogger( name ) method this is done for
you. If you make your own logger for some reason, you can still use the
LogManger to cache it.

Then, I wrote a version using a named logger and a single class variable
and the whole thing looks a lot simpler and cleaner:


It's kind of six of one and half dozen of another. Do what makes you
happiest. But assume any given shop might have different ideas what is
best, and be prepared to adjust.
 
N

Novice

I can not see why saving to type something that give the class name
should be smart even for small things.


Loggers are cached by default.

I have only used LogManager when I wanted to work
with the config.

If I'm understanding you correctly - and please tell me if I'm not - then
there's nothing wrong with the approach I've used in the second program,
LoggingTest2. That's good to know!
 
N

Novice

markspace said:
I could see an app that was divided into functional parts, like maybe
"DATABASE" and "GUI", etc. where the logging was specified to use
those names:

Logger log = Logger.getLogger( "GUI" );

But while I could see this, I've never actually heard of anyone
specifying it. Loggers by class name is all I've ever seen.



I think I've done this, exactly once in my life:

public class MyLogger extends Logger {
...
}

...
MyLogger log = new MyLogger();
LogManager.getLogManager().addLogger( log );

If you go through the Logger.getLogger( name ) method this is done for
you. If you make your own logger for some reason, you can still use
the LogManger to cache it.




It's kind of six of one and half dozen of another. Do what makes you
happiest. But assume any given shop might have different ideas what
is best, and be prepared to adjust.


I'm completely fine with that. This seems like the kind of thing where
there are several good approaches (or maybe several variations on one
good approach). In a reasonable world, no one would hold it against me if
I used a slightly different variation than they did, as long as I
complied with their standards when writing for their shop.

I just wanted to make sure I wasn't missing something that made
Stelting's approach dramatically better than mine.
 
A

Arne Vajhøj

I could see an app that was divided into functional parts, like maybe
"DATABASE" and "GUI", etc. where the logging was specified to use those
names:

Logger log = Logger.getLogger( "GUI" );

But while I could see this, I've never actually heard of anyone
specifying it. Loggers by class name is all I've ever seen.

That is generally accepted best practice.

And assuming that database or gui classses are all in a single
package or a single subtree of packages, then one can managed
them just fine via the full class name model.

Arne
 
A

Arne Vajhøj

If I'm understanding you correctly - and please tell me if I'm not - then
there's nothing wrong with the approach I've used in the second program,
LoggingTest2. That's good to know!

I would use a static logger and not call getLogger in every ctor.

Not due to performance, because I don't think there will be much,
but because I think it is nice to keep that type of non business
logic out of the ctor, so that when one read the ctor one can focus
on the real purpose of it.

Arne
 
A

Arved Sandstrom

That is generally accepted best practice.

And assuming that database or gui classses are all in a single
package or a single subtree of packages, then one can managed
them just fine via the full class name model.

Arne

I've mentioned a few times in the past some projects I've worked on
where we substantially changed the logging in a number of J2EE/Java EE
apps for a client. Improved I'd like to think, at least that's what the
ops support people for the client have opined for a few years now, and
that's what matters.

We did build in the ability to specify "functional parts" or "functional
areas", exactly like "DATABASE" or "GUI" (although in our case it was
quite a bit more discrete). But this was incorporated as part of the
message text (the %m part of log4j PatternLayout); it's not something
that log4j as a framework knows anything about. It's best thought of as
an informal, extra conversion specifier in PatternLayout. We also put in
authenticated userID in the same way.

I might add, enough [1] "functional parts" or subsystems in a JEE app
tend to crosscut Java packages that relying merely on the logging
framework and classname-specified loggers to reflect this usually
doesn't work. It's not so much for managing loggers that you might do
something like I describe, it's for the benefit of analyzing logs with
grep or Splunk or what have you. For managing loggers through the
framework config files it's still a matter of configuring loggers at
package or class level in the usual way, so "loggers by class name" is
absolutely the way to go still.

AHS

1. Just what it says. :) Many, maybe most, functional subsystems in a
JEE app map rather cleanly to packages. Application/service layer
functional subsystems tend to do that. But a number of subsystems don't
always map cleanly to packages.
 
L

Lew

Arne said:
I would use a static logger and not call getLogger in every ctor.

Not due to performance, because I don't think there will be much,
but because I think it is nice to keep that type of non business
logic out of the ctor, so that when one read the ctor one can focus
on the real purpose of it.

I prefer instance loggers, as a rule but not always. For one thing this allows
me to determine the logger's identity via a call to 'getClass()'. Mainly,
though, it's the scope of the variable. In an instance context I prefer
instance or local variables. In a static context I prefer local variables,
occasionally static memebers. I determine the scope of the logger variable by
the scope of its use.

Logging is a standard enough aspect that I don't find it offputting in the logic.
 
A

Arne Vajhøj

I prefer instance loggers, as a rule but not always. For one thing this
allows me to determine the logger's identity via a call to 'getClass()'.

But using Foobar.class is refactorable as well.
Mainly, though, it's the scope of the variable. In an instance context I
prefer instance or local variables. In a static context I prefer local
variables, occasionally static memebers. I determine the scope of the
logger variable by the scope of its use.

Logging is a standard enough aspect that I don't find it offputting in
the logic.

For instance I would still prefer to have getLogger assignment in the
definition and not down in the ctor.

Arne
 
R

Robert Klemme

I prefer instance loggers, as a rule but not always. For one thing this allows
me to determine the logger's identity via a call to 'getClass()'.

We should mention that this is not exactly equivalent from the logging point of view. The common approach with a static member ensures that all log statements which are generated from methods in the class carry that class's name. Your approach will lead to different class names for different (sub-) class instances. Whether that is desirable or not is another question but it is certainly a difference one should be aware of - especially when setting up filtering in the logger.

Kind regards

robert
 
M

markspace

We should mention that this is not exactly equivalent from the
logging point of view.


Also be aware that while static loggers are common in Java in general,
instance loggers are recommended best practice according the the Apache
Commons website.


Context, requirements, etc.
 
A

Arne Vajhøj

Also be aware that while static loggers are common in Java in general,
instance loggers are recommended best practice according the the Apache
Commons website.

Is this the same arguments that we discussed last week?

Arne
 
L

Lew

Arne said:
For instance I would still prefer to have getLogger assignment in the
definition and not down in the ctor.

If you mean something like

public class Foo
{
private final Logger logger = getLogger(getClass().getName());
// ...
}

until now I thought you were including that when you said "in the ctor".

Now I understand you to mean "explicitly within the declared body of a constructor" as opposed to logically in the constructor.
 
A

Arne Vajhøj

If you mean something like

public class Foo
{
private final Logger logger = getLogger(getClass().getName());
// ...
}
Yes.

until now I thought you were including that when you said "in the ctor".

Now I understand you to mean "explicitly within the declared body of a constructor" as opposed to logically in the constructor.

Sorry for the confusion.

Arne
 
R

Robert Klemme

Also be aware that while static loggers are common in Java in general,
instance loggers are recommended best practice according the the Apache
Commons website.

I think this is not exactly true if you are referring to this:

"Note that for application code, declaring the log member as "static" is more efficient as one Log object is created per class, and is recommended. However this is not safe to do for a class which may be deployed via a "shared" classloader in a servlet or j2ee container or similar environment. If the class may end up invoked with different thread-context-classloader valuesset then the member must not be declared static. The use of "static" should therefore be avoided in code within any "library" type project."

http://commons.apache.org/logging/guide.html

Truth is that static loggers are recommended for application code; only forlibrary code they recommend against static loggers.

Kind regards

robert
 
L

Lew

Robert said:
I think this is not exactly true if you are referring to this:

"Note that for application code, declaring the log member as "static" is more efficient as one Log object is created per class, and is recommended. However this is not safe to do for a class which may be deployed via a "shared" classloader in a servlet or j2ee container or similar environment. If the class may end up invoked with different thread-context-classloader values set then the member must not be declared static. The use of "static" should therefore be avoided in code within any "library" type project."

Declaring a log member as 'static' is not more efficient. What are they
talking about?

When advice is clearly baloney, you can disregard it.
http://commons.apache.org/logging/guide.html

Truth is that static loggers are recommended for application code; only for library code they recommend against static loggers.

Either way you take it, their recommendation is BS.
 
M

markspace

Declaring a log member as 'static' is not more efficient. What are they
talking about?


Probably the blindingly obvious point that O(1) instantiation of the
logger is better than a per-object O(n) instantiation.



By "application" do you mean JEE app or desktop app?

Either way, I don't understand your assertion. Why would static vs.
instance make any difference in a library, assuming no shared or other
special classloaders are in use?
 
A

Arne Vajhøj

Probably the blindingly obvious point that O(1) instantiation of the
logger is better than a per-object O(n) instantiation.

????

static => initialize 1 instance

non static => initialize 1 instance and lookup in HashMap for each ref
assignment

Arne
 
A

Arne Vajhøj

I think this is not exactly true if you are referring to this:

"Note that for application code, declaring the log member as "static" is more efficient as one Log object is created per class, and is recommended. However this is not safe to do for a class which may be deployed via a "shared" classloader in a servlet or j2ee container or similar environment. If the class may end up invoked with different thread-context-classloader values set then the member must not be declared static. The use of "static" should therefore be avoided in code within any "library" type project."

http://commons.apache.org/logging/guide.html

Truth is that static loggers are recommended for application code; only for library code they recommend against static loggers.

????

Isn't that the argument we discussed last week and after Arveds test
could conclude was completely BS?

Arne
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top