Logging

Overview

MASS-Core provides a logging facility tuned for performance with Agent-based systems. Currently the logger is built on Apache Log4J-2 with the SLF4J facade, configured for asynchronous writes to the filesystem of each node.

Apache Log4J-2 was chosen for it’s performance over traditional Java-based logging (java.util.logging). SLF4J, a logging facade, was chosen to help abstract out the implementation of a logger within MASS and make it easier to experiment with different logging mechanisms in the future.

The MASS-Core logging facility is available for applications to use, and it is recommended that applications developed using MASS take advantage of this facility for performance and simplicity of use.

Using the Logger in Your Applications

NOTE: It is not necessary to use the MASS Logger in your application; in fact, you may use any logger of your choice in your applications, **except for “System.out.*“**. Communications between nodes rely on several channels, one of which is the console (“stdout”). Sending messages to the console on remote nodes will disrupt communications and prevent proper operation of MASS.

Log Levels

The logger operates in one of several modes of operation (in descending order of “priority”):

The default setting for the logger is ERROR. In this setting, the only messages recorded are those resulting from application or library exceptions. Except for OFF, this is the highest logging level and is most typically used after the application has been debugged and is being run normally. DEBUG is the lowest priority level and will cause the logger to output all messages. You should use DEBUG only while testing and validating your application; afterwards either set the log level to WARN or ERROR. If you experience errors that do not seem to be the fault of your application, or if you wish to validate the operation of the MASS library, use the TRACE logging level to output all debugging messages from your application and from the library. The TRACE logging level will generate large log files and will have the greatest impact on performance.

You should set the logging level as soon as practicable in your application as follows:

#!java
    MASS.setLoggingLevel( LogLevel.DEBUG );

The LogLevel enumeration specifies which logging level should be used.

Logging Exceptions

You can log detailed exception messages like this example:

#!java
    try {
        
        // statements that may trigger an Exception
        
    }
    catch ( Exception e ) {
        
        // something really horrible happened, need to log it!
        MASS.getLogger().error( "My application threw an Exception while trying to XXXXX!", e );
        
        // react appropriately to this Exception
        
    }

In the above example, the Exception instance is passed to the logger for detailed reporting of the error message and stacktrace.

If you do not have access to the Exception object, or wish to record an error condition without an Exception being generated, use this method instead:

#!java
    MASS.getLogger().error( "My application encountered an error state while trying to XXXXX!" );

Logging Debug Messages

You may record messages for application debugging purposes as follows:

#!java
    MASS.getLogger().debug( "Attempting to connect to the database..." );
    db.initConnection();
    MASS.getLogger().debug( "Database connected!" );

Please refer to the section of this article titled “Performance Considerations” for important tips on logging debug messages with minimum impacts on application performance.

Logging Warnings

To record a warning message (in version 1.1.0 of MASS-Core and later), use the following method:

#!java
    MASS.getLogger().warning( "This is an application-generated warning!" );

Performance Considerations

The logging facility in MASS was designed with performance in mind; the following tips will help balance the need to record messages and the need for performance:

#!java
    private static final boolean DEBUG_MODE = false;
    
    // application code...
    
    if ( DEBUG_MODE ) MASS.getLogger().debug( "Finished Initialization!" );

The logger contains an efficient means for determining if a message should be logged based on the LogLevel. In the code example listed above, if the application was actually running in DEBUG logging mode, there would actually be two checks (DEBUG_MODE and LogLevel.DEBUG) required to see if a message should be recorded. If the application was running in ERROR logging mode, there would be little or no improvement in execution time checking for the boolean DEBUG_MODE value versus allowing the logger to verify it’s operating mode. NOTE: There is a special consideration for constructing logging messages at run-time (next tip).

#!java
    MASS.getLogger().debug( "Calculating new values for {} places ", totalPlaces );

Note the inclusion of the curly braces. When the logger records this message, it will place the value of “totalPlaces” in place of the curly braces.

The purpose for this special construct is to prevent the instantiation of multiple String objects. The performance benefit is realized when the logger is set to a mode other than DEBUG; if the “debug()” method is called while running in ERROR mode, for example, the logger will not attempt to construct the message and no additional objects will be created. This construct is important because it allows you to (next tip)…

The developers of both MASS and Apache Log4J-2 recommend leaving logging methods in your application and using the LogLevel setting to determine which messages are actually recorded. With this in mind, the expense of calling logging methods such as “debug()” has been minimized when the logger is running at a higher level (such as “OFF” or “ERROR”). There is actually no benefit to using the traditional “DEBUG boolean” pattern as shown in tip #1, and removing the logging statements from your application would result in little gain. Leaving logging method calls in place and using different LogLevels will give maximum flexibility and very little (if any) sacrifice in performance.

Notes for MASS-Core Library Developers