Loggifier.unkrig.de: Difference between revisions

From unkrig.de
Jump to navigation Jump to search
(Die Seite wurde neu angelegt: „== Getting started with LOGGIFIER == Now you want to know how you can use the LOGGIFIER. I presume that you know what java.util.logging is and why you want to…“)
 
mNo edit summary
Line 145: Line 145:


LOGGIFIER is not only available as a command-line tool, but also as an ECLIPSE plug-in and an ANT task.
LOGGIFIER is not only available as a command-line tool, but also as an ECLIPSE plug-in and an ANT task.
== Download ==
To get the LOGGIFIER ECLIPSE plugins, define an update site
    <nowiki>http://loggifier.unkrig.de/update/</nowiki>
in "Help / Install new software...".
To get the JAR files mentioned above, download them from
    http://loggifier.unkrig.de/download/
The source code is available through SVN:
    https://svn.code.sf.net/p/loggifier/code

Revision as of 10:31, 30 May 2013

Getting started with LOGGIFIER

Now you want to know how you can use the LOGGIFIER. I presume that you know what java.util.logging is and why you want to use logging at all (e.g. in favor of an interactive debugger).

So let's start with a very simple program:

   import java.util.logging.Logger;
   
   public class Main {
   
       private static final Logger LOGGER = Logger.getLogger("Main.USER");
   
       public static void main(String[] args) {
           System.out.println("HELLO WORLD");
           LOGGER.fine("About to terminate");
       }
   }

By default, java.util.logging is disabled, so we won't get any logging output:

   $ javac Main.java
   $ java Main
   HELLO WORLD
   $

Thus we need to create one more file

   # File 'my_logging.properties'.
   handlers = java.util.logging.ConsoleHandler
   java.util.logging.ConsoleHandler.level = FINEST
   .level = FINEST

, and run our program with the 'java.util.logging.config.file' system property set:

   $ java -Djava.util.logging.config.file=my_logging.properties Main
   HELLO WORLD
   26.08.2011 11:01:53 Main main
   FINE: About to terminate
   $

(If you don't like the two-line output format, then you can configure a different log formatter, e.g. 'de.unkrig.commons.util.logging.formatter.PrintfFormatter', contained in de.unkrig.commons.jar, in the 'my_logging.properties' file:

   java.util.logging.ConsoleHandler.formatter = de.unkrig.commons.util.logging.formatter.PrintfFormatter
   de.unkrig.commons.util.logging.formatter.PrintfFormatter.format = COMPACT

Then you'll get:

   $ java -Djava.util.logging.config.file=my_logging.properties -cp de.unkrig.commons.jar\;. Main
   HELLO WORLD
   FINE Main::main About to terminate
   $

But that's only a matter of taste.)

So now let's loggify the 'Main' class! Get 'de.unkrig.loggifier.jar' and 'de.unkrig.loggifier-runtime.jar' from [1] and run:

   $ ls -l
   -rwx------+ 1 H7DA016 Kein 969 Aug 26 11:23 Main.class
   $ java -cp de.unkrig.loggifier.jar de.unkrig.loggifier.Main Main.class
   $ ls -l
   -rwx------+ 1 H7DA016 Kein 2314 Aug 26 11:23 Main.class
   $

Not only can you pass class files to LOGGIFER, but also directories, files in ZIP format that contain '.class' files (e.g. JAR and WAR files), and even ZIP files that contain nested ZIP files with '.class' files (e.g. EAR files). In any case, LOGGIFIER will modify the contained '.class' "in-place".

Now what logging do we get now?

   $ java -Djava.util.logging.config.file=my_logging.properties -cp de.unkrig.commons.jar\;de.unkrig.loggifier-runtime.jar\;. Main
   FINER Main::<clinit>() (Main.java:5) ENTRY  args=()
   FINER Main::<clinit>() (Main.java:5) RETURN
   FINER Main::main(String[]) (Main.java:8) ENTRY  args=(String[0])
   HELLO WORLD
   FINE Main::main About to terminate
   FINER Main::main(String[]) (Main.java:10) RETURN
   $

Notice that you now need to have the (very small) 'de.unkrig.loggifier-runtime.jar' on the class path, because the injected logging code needs that.

By default, LOGGIFIER injects a 'reasonable' amount of logging: You can see how the class initializer of the 'Main' class is executed, then how the 'main()' method is executed. Notice how the hand-written logging seamlessly mixes with the automatically injected logging.

Effectively, we can now remove the hand-written logging code from our class, because the automatically injected logging code now does the job:

   public class Main {
   
       public static void main(String[] args) {
           System.out.println("HELLO WORLD");
       }
   }

Now let's compile, loggify and run again:

   $ javac Main.java
   $ java -cp de.unkrig.loggifier.jar de.unkrig.loggifier.Main Main.class
   $ java -Djava.util.logging.config.file=my_logging.properties -cp de.unkrig.commons.jar\;de.unkrig.loggifier-runtime.jar\;. Main
   FINER Main::<clinit>() (Main.java:5) ENTRY  args=()
   FINER Main::<clinit>() (Main.java:5) RETURN
   FINER Main::main(String[]) (Main.java:8) ENTRY  args=(String[0])
   HELLO WORLD
   FINER Main::main(String[]) (Main.java:10) RETURN
   $

For demonstration, we now set the amount of logging to the highest possible level. There are several ways to configure the injection of logging code: We can pass a 'rule' to the LOGGIFER like '-rule ALL=FINE', or add a '@Loggify' annotation to any class or method declaration:

   import de.unkrig.loggifier.runtime.annotation.Loggify;
   
   @Loggify("ALL=FINE")
   public class Main {
       // ...

Then compile, loggify and run again:

   $ javac Main.java -cp de.unkrig.loggifier-runtime.jar
   $ java -cp de.unkrig.loggifier.jar de.unkrig.loggifier.Main Main.class
   $ java -Djava.util.logging.config.file=my_logging.properties -cp de.unkrig.loggifier-runtime.jar\;de.unkrig.commons.jar\;. Main
   FINE Main::<clinit>() (Main.java:1) CLINIT Main
   FINE Main::<clinit>() (Main.java:7) ENTRY  args=()
   FINE Main::<clinit>() (Main.java:7) CONST  "Main.USER"
   FINE Main::<clinit>() (Main.java:7) INVOKE Logger.getLogger(String): args=("Main.USER")
   FINE Main::<clinit>() (Main.java:7) RESULT Logger.getLogger(String) => java.util.logging.Logger@156ee8e
   FINE Main::<clinit>() (Main.java:7) PUT    Main.LOGGER <== java.util.logging.Logger@156ee8e
   FINE Main::<clinit>() (Main.java:7) RETURN
   FINE Main::main(String[]) (Main.java:10) ENTRY  args=(String[0])
   FINE Main::main(String[]) (Main.java:10) GET    System.out ==> java.io.PrintStream@47b480
   FINE Main::main(String[]) (Main.java:10) CONST  "HELLO WORLD"
   FINE Main::main(String[]) (Main.java:10) INVOKE PrintStream.println(String): target=java.io.PrintStream@47b480, args=("HELLO WORLD")
   HELLO WORLD
   FINE Main::main(String[]) (Main.java:10) RESULT PrintStream.println(String)
   FINE Main::main(String[]) (Main.java:12) RETURN
   $

(Notice that JAVAC now needs "de.unkrig.loggifier-runtime.jar" on the class path, because "@de.unkrig.loggifier.runtime.annotation.Loggify" lives there.)

Now you also get informed how the 'System.out' field is read and the string constant "HELLO WORLD" is used - if you're interested.

LOGGIFIER is not only available as a command-line tool, but also as an ECLIPSE plug-in and an ANT task.

Download

To get the LOGGIFIER ECLIPSE plugins, define an update site

   http://loggifier.unkrig.de/update/

in "Help / Install new software...".

To get the JAR files mentioned above, download them from

   http://loggifier.unkrig.de/download/

The source code is available through SVN:

   https://svn.code.sf.net/p/loggifier/code