![]() |
Java LoggingRussell Bateman |
Formally known as Java Logging (or juli in Tomcat), because java.util.logging implementation, is native to Java; there is no need for a third-party JAR.juli is not as nice as Logback, but nothing else really works, especially if you want to be instantly successful and save yourself much trouble, with Tomcat.
Note that slf4j is a facade atop any logging framework (including log4j, logback and even juli).
Configuration is done using standard java.util.Properties format, typically in a file named logging.properties, under the classes subdirectory of the JAR or WAR (WEB-INF/classes). For example, in the IDE on the path src/main/resources/logging.properties (and/or src/test/resources/logging-test.properties).
Then, when running inside the IDE, these will just be found and used.
However, when running outside the IDE (i.e.: in actual production), do this:
$ java -Djava.util.logging.config.file=logging.properties -cp my-application.jar com.windofkeltia.application.Main
my-application.war/WEB-INF/classes/logging.properties which Tomcat will deploy sciently.
For host-wide configuration (unlikely), the configuration file can be placed on the path ${JAVA_HOME}/conf.
# Support both a console handler (most often seen in IDE) and a file handler handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler # Default global logging level--all loggers (not really needed because each handler specifies here) .level= INFO # File handler; default output is in user's home directory. java.util.logging.FileHandler.level = INFO 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.maxLocks = 100 java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter # Console handler java.util.logging.ConsoleHandler.level = INFO java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter # Customize the SimpleFormatter output format # level: log message [date/time] java.util.logging.SimpleFormatter.format = %4$s: %5$s [%1$tc]%n # Constrain logging per package path com.windofkeltia.utilities.level = SEVERE com.windofkeltia.parser.level = INFO com.windofkeltia.servlet.level = WARN
package com.windofkeltia.foo; import java.util.logging.Logger public class Foo { private static Logger logger = Logger.getLogger( Foo.class.getName() ); public static void main( String argv[] ) { logger.finest( "doing stuff" ); // like Logback's logger.trace( "main()" ); try { Foo.sneeze(); } catch ( Exception e ) { logger.log( Level.WARNING, "trouble sneezing", e ); // logger.warning( ... ); } logger.fine( "done" ); // like Logback's logger.debug( "done " ); } }
Let's compare them to Logback.
JULI | Logback |
---|---|
FINEST | TRACE |
FINER | TRACE/DEBUG |
FINE | DEBUG |
INFO | INFO |
WARNING | WARN |
SEVERE | ERROR |
ALL | (gets dim for me) |
OFF | OFF (as I recall) |
CONFIG | Reveal logging configuration (in the log) |
import java.util.logging.Logger; public class Foo { private static final Logger logger = Logger.getLogger( Foo.class.getName() ); ...
logger.log( Level.FINE, "Processing {0} entries in loop", list.size() ); // or: logger.fine( "Processing {0} entries in loop", list.size() );
logger.log( Level.FINER, "Blah, blah, blah..." ); // or: logger.finer( "Blah, blah, blah..." );
logger.finer( "Processing {0} entries in loop", list.size() ); // instead of: logger.finer( "Processing " + list.size() + entries in loop" );
try { .. } catch( Exception e ) { logger.severe( e.toString(), e ); }
Note: passing e.toString() causes (e.getMessage()) to be put into the log statement on the same line. That way, fgrep'ing for "Exception" will show the message and no advanced regular expression string(d) need be created to match the log statement.