5.14. Logging

Purpose - to provide an api for debug log and trace messages.

The purpose of debug log and trace messages is: To provide a mechanism that allows the developer to enable output of minor events focused on a specific problem area and to follow what is going on inside ArgoUML.

The Logging is located in org.argouml.???

The Logging is a Layer 0 subsystem.

Logging is currently implemented using log4j.

ArgoUML uses the standard log4j logging facility. The following sections deal with the current implementation in ArgoUML. By default, logging is turned off and only the version information of all used libraries are shown on the console.

5.14.1. What to Log in ArgoUML

Logging entries in log4j belong to exactly one level.

  • The FATAL level designates very severe error events that will presumably lead the application to abort. Everything known about the reasons for the abortion of the application shall be logged.

  • The ERROR level designates error events that might still allow the application to continue running. Everything known about the reasons for this error condition shall be logged.

  • The WARN level designates potentially harmful situations. This is if CG can't find all the information required and has to make something up.

  • The INFO level designates informational messages that highlight the progress of the application at coarse-grained level. This typically involves creating modules, subsystems, and singletons, loading and saving of files, imported files, opening and closing files.

  • The DEBUG Level designates fine-grained informational events that are most useful to debug an application. This could be everything happening within the application.

This list is ordered according to the priority of these logging entries i.e. if logging on level WARN is enabled for a particular class/package, all logging entries that belong to the above levels ERROR and FATAL are logged as well.

For performance reasons, it is advised to do a check before frequently passed DEBUG and INFO log4j messages (see Example 5.2, “Improving on speed/performance”). The purpose of this test is to avoid the creation of the argument.

5.14.2. How to Create Log Entries...

You should not use System.out.println in ArgoUML Java Code. The only exception of this rule is for output in non-GUI mode like to print the usage message in Main.java.

To make log entries from within your own classes, you just need to follow the three steps below:

  1. Import the org.apache.log4j.Logger class

  2. Get a Logger

  3. Start Logging...

Example 5.1. For log4j version 1.2.x

import org.apache.log4j.Logger;
...
public class theClass {
...
    private static final Logger LOG = 
        Logger.getLogger(theClass.class);

...

    public void anExample() {
        LOG.debug("This is a debug message.");
        LOG.info("This is a info message.");
        LOG.warn("This is a warning.");
        LOG.error("This is an error.");
        LOG.fatal("This is fatal. The program stops now working...");
    }
            

Notice that we in the ArgoUML project have decided to have all loggers private static final with a static initializer. The reason for making them private is that this reduces the coupling between classes i.e. there is no risk that one class uses some other class' Logger to do logging. The reason for making them static is that our classes are more or less all either lightweight, like a representation of an object in the model, or a singleton. For the lightweight classes, having a reference to a logger object per object is a burden and for the singleton objects it doesn't care if the logger is static or not. The reason for making this final is that it shall never be modified by the class. The reason for having a static initializer is that then all classes can do this in the same way and we don't ever risk to forgot to create the Logger.

For performance reasons, a check before the actual logging statement saves the overhead of all the concatenations, data conversions and temporary objects that would be created otherwise. Even if logging is turned off for DEBUG and/or INFO level.

Example 5.2. Improving on speed/performance

    if (LOG.isDebugEnabled()) {
        LOG.debug("Entry number: " + i + " is " + entry[i]);
    }
    if (LOG.isInfoEnabled()) {
        LOG.info("Entry number: " + i + " is " + entry[i]);
    }
            

[Warning]Warning

Since this has a big impact also on the readability, only use it where it is really needed (like places passed several times per second or hundreds of times for every key the user presses).

For more information go to the log4j homepage at http://jakarta.apache.org/log4j.

5.14.2.1. Reasoning around the performance issues

Most of the log statements passed in ArgoUML are passed with logging turned off. This means that the only thing log4j should do is to determine that logging is off and return. Log4j has a really quick algorithm to determine if logging is on for a certain level so that is not a problem.

The problem is instead explained by noticing the following log statement:

        int i;
...
        LOG.debug("Entry number: " + i + " is " + entry[i]);
	    

It is quite innocent looking isn't it? Well that is because the java compiler is very helpful when it comes to handling strings and will convert it to the equivalent of:

	StringBuffer sb = new StringBuffer();
	sb.append("Entry number: ");
	sb.append(i);
	sb.append(" is ");
	sb.append(entry[i].toString());
        LOG.debug(sb.toString());
	    

If the entry[i] is some object with a lot of calculations when toString() is called and the logging statement is passed often some action needs to be taken. If the toString() methods are simple you are still stuck with the overhead of creating a StringBuffer (and a String from the sb.toString()-statement.

5.14.3. How to Enable Logging...

log4j uses the command line parameter -Dlog4j.configuration = URL to configure itself where URL points to the location of your log4j configuration file.

Example 5.3. Various URLs

org/argouml/resource/filename.lcf              1

http://localhost/shared/argouml/filename.lcf   2

file://home/username/filename.lcf              3
            
1

Reference to a configuration file filename.lcf within argouml.jar.

2

Reference to a configuration file filename.lcf on a remote server/localhost.

3

Reference to a configuration file filename.lcf on your localmachine.

5.14.3.1. ...when running ArgoUML from the command line

There are currently two possibilities of running ArgoUML from the command line:

  1. Run ArgoUML using argouml.jar

  2. Run ArgoUML using the ant script

In the first case, the configuration file is specified directly on the command line, whereas in the latter case this parameter is specified in the build.xml (which in that case needs to be modified). ArgoUML is then started as usual with ./build run.

Example 5.4. Command Line for argouml.jar

[localhost:~] billy% java -Dlog4j.configuration=URL -jar argouml.jar                        
                

Example 5.5. Modification of build.xml

<!-- =================================================================== -->
<!-- Run ArgoUML from compiled sources                                   -->
<!-- =================================================================== -->
<target name="run" depends="compile">
    <echo message="--- Executing ${Name} ---"/>
    <!-- Uncomment the sysproperty and change the value if you want -->
    <java classname="org.argouml.application.Main"
          fork="yes"
          classpath="${build.dest};${classpath}">
          < sysproperty key="log4j.configuration"
                       value="org/argouml/resource/filename.lcf"></sysproperty>
    </java>
</target>
                

5.14.3.2. ...when running ArgoUML from WebStart

To view the console output, the WebStart user has to set Enable Java Console in the Java WebStart preferences. In the same dialog, there is also an option to save the Console Output to a file.

As you cannot provide any userspecific parameters to a WebStart Application from within WebStart, it is currently not possible to choose log4j configuration when running ArgoUML from Java Web Start.

5.14.3.3. ...when running ArgoUML from NetBeans

At the time of writing this paragraph, it is not possible to set the logging configuration file on a per project basis in NetBeans. Instead, the Global Options of [Debbuging and Execution/Execution Types/External Execution/External Process] need to be changed.

Example 5.6. External Execution Property (Arguments)

-cp {filesystems}{:}{classpath}{:}{library} -Dlog4j.configuration=URL
    {classname} {arguments}
                

5.14.4. How to Customize Logging...

There are some sample configuration files provided in org.argouml.resource. Modify these according to your needs. Or alternatively, you can try configLog4j to assist yourself in creating a log4j configuration file.

5.14.5. References