Creating Log Messages
Estimated time to read: 5 minutes
Since Java 1.4, Java has had a logging library built in. It is located in the java.util.logging
package.
Log4J is an alternative logging library that may be used in real wold applications. For more info, see Log4J
Schematic Design¶
Something in the code triggers a log event
An instance of the Logger
class stars processing the log event, it can optionally filter the information first.
Data from the Logger
instance is stored in a LogRecord
instance.
The data within the LogRecord
instance is then passed to a Handler
. Optionally, the Handler
can have additional rules for filtering and formatting.
The Handler
then passes the data to the Log File, where the data is recorded and stored.
A LogManager
influences the entire process.
Creating a Logger¶
The follow code example shows how a logger is created and added to a project
package io.entityfour.logmodule;
import java.util.logging.Logger;
public class LogExample {
private static final Logger LOGGER = Logger.getLogger(LogExample.class.getName()); // Instantiating the logger here, whilst setting its accessibility to private and final, is a better approach. Note that the instance name is now LOGGER as it is a constant / final.
public static void main(String[] args) {
// Logger.getLogger(); // This will set up a basic logger, however, it is common to give the logger a name!
// Logger.getLogger(LogExample.class.getName()); // Convention is that the logger name is the same as the class name. You can use the <classname>.class.getName() method to do this for you.
//Logger logger = Logger.getLogger(LogExample.class.getName()); // Instantiate the logger. This can be done here in the method, however, it is better for this to be encapsulated and include above the class. This way, a private modifier can be used so that the logger is exclusive to this class.
// logger.log(Level.INFO, "This is an example INFO level log)"); // The log() method takes a log level, followed by a message as it arguments. It will log to the console by default!
LOGGER.log(Level.INFO, "This is a new INFO level log message"); // As the logger has now been created as a constant / final, it can be called by its new instance name.
}
}
Log Levels¶
Log levels are used to distinguish between different levels of severity of a situation.
There are seven levels in the Java logging API.
These levels get translated to a number via an Enum, the higher the number; the more severe the situation.
In descending order of severity, these levels are:
- SEVERE
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST
By default, a Logger
and Handler
are created with INFO as their default level. Levels below this, such as CONFIG, FINE, etc will not be output.
Note
If the Logger
instance is set to a non-default level, such as FINE, if the Handler
isn't set up with a non-default level of the same or lower value, the Handler
will not report the line.
Logger Level Implementation¶
package io.entityfour.logmodule;
import java.util.logging.Logger;
public class LogExample {
private static final Logger LOGGER = Logger.getLogger(LogExample.class.getName());
public static void main(String[] args) {
LOGGER.setLevel(Level.FINEST); // Set the Logger's level to FINEST
LOGGER.log(Level.FINEST, "This is a mighty fine message"); // This will not print! Despite the Logger's level being set above, the Handler's level has not been set!
}
}
The example above will not print anything out to the console.
When using Logger
, the default handler is set as the output console which has its default level set to INFO.
The FINEST log level message did not print as it was filtered out by the Handler
's level configuration.
Log Handlers¶
A Handler
exists to direct messages to the log location such as the command line, a log file or an external service. However, messages will only be passed to a log location if Handler
s filter configuration allows it to. Handler
s also format the message using a formatter.
There are many types of handlers, such as:
- ConsoleHandler (Default)
- FileHandler
- StreamHandler
- SocketHandler
- MemoryHandler
Console Handler Implementation¶
package io.entityfour.logmodule;
import java.util.logging.Logger;
public class LogExample {
private static final Logger LOGGER = Logger.getLogger(LogExample.class.getName());
static { // This is known as an 'Initializer Block'. Cod e that is declared here will run each time an instance of the object (Class) is created.
LOGGER.setLevel(Level.FINEST);
ConsoleHandler consoleHandler = new ConsoleHandler(); // Instantiate a ConsoleHandler
consoleHandler.setLevel(Level.FINEST); // Set the Handlers level to FINEST
LOGGER.addHandler(consoleHandler); // Assign the handler to the logger
}
public static void main(String[] args) {
LOGGER.log(Level.FINEST, "This is a mighty fine message");
}
}
File Handler Implementation¶
package io.entityfour.logmodule;
import java.util.logging.Logger;
public class LogExample {
private static final Logger LOGGER = Logger.getLogger(LogExample.class.getName());
static {
FileHandler fileHandler = null; // Create a FileHandler object with a null value
try { // Wrap the fileHandler instantiation with try/catch to catch any exceptions
fileHandler = = new FileHandler(<className>.class.getSimpleName() + ".log");
} catch (IOException e){
e.printStackTrace();
}
LOGGER.addHandler(fileHandler); // Assign the handler to the logger
}
public static void main(String[] args) {
LOGGER.log(Level.FINEST, "This is a mighty fine message");
}
}
Logging Methods¶
There are three log methods, with each offering many overloaded constructors for logger creation.
LOGGER.logp(Level.<LOGLEVEL>, <CLASSNAME>.class.getName(), <STR_METHODNAME>, <STR_MESSAGE>);
LOGGER.logrb(Level.<INFO>, ResourceBundle.getBundle("en_US"), <STR_MESSAGE>);
Best Practices¶
Be Precise¶
The log entry should answer who, when, where, what and the result. For example, User Logged In
is not as verbose as User: jSmith, ID:12, Login:success, Date:03/04/2022, Time:11:25:43
No sensitive data¶
Logs are often stored on external platforms or systems. Logs may be accessed for many purposes by many people. As a result, ensure that sensitive data is not stored in the log file.
Correct log level¶
It is important to use the correct log level to report a message to the log.
Machine and Human readable¶
Logs should be Machine and Human readable. This allows the log to be processed via automated processes whilst also allowing someone to read the log naturally. Formatting is key.
Don't log too much¶
Logging too much can reduce the performance of the application and also fill up the log file with unnecessary detail.
Don't log too little¶
Conversely, don't log too little!