Path: csiph.com!usenet.pasdenom.info!aioe.org!.POSTED!not-for-mail From: Novice Newsgroups: comp.lang.java.programmer Subject: Question about loggers Date: Wed, 7 Mar 2012 21:52:35 +0000 (UTC) Organization: Your Company Lines: 185 Message-ID: NNTP-Posting-Host: aorhoX7wqL+zg222N4gRzA.user.speranza.aioe.org X-Complaints-To: abuse@aioe.org User-Agent: Xnews/5.04.25 X-Antivirus-Status: Clean X-Notice: Filtered by postfilter v. 0.8.2 X-Antivirus: avast! (VPS 120307-0, 2012-03-07), Outbound message Xref: csiph.com comp.lang.java.programmer:12750 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 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 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. -- Novice