The logging described here has nothing to do with the internal ADEPT2-logging
used for tracking changes in process states or structures (execution history,
data history, change history). Merely, this logging is used for implementation
issues as error messages and debugging.
Logging
To avoid the messy System.out.println(...) for error messages
throughout the code, the Java-Logging is used (see
java.util.logging).
Java logging
The logging in Java is based on a logger hierarchy which is reflected in the
name of the Loggers. "" is the root logger that gets all log messages.
All other loggers have arbitrary names, whereas a hierarchy is defined similar
to the java-package mechanism, for instance, hierarchy1.Logger1,
hierarchy1.Logger2, hierarchy1.subhierarchy1.Logger1,
hierarchy2.Logger1,... Parent loggers also log messages of child
loggers.
Despite the similarity, this hierarchy is strictly separated from the package
structure as well as the class hierarchy. The name of the method and the full
name of the corresponding class are implicitly logged and thus allowing a
very flexible and completely detached logger hierarchy.
Providing loggers in ADEPT2
In ADEPT2 every class has its own (protected and final) class field for its
logger (if needed). The logger has its own name which equals the name of the
class (including package).
When subclassing one should pay attention to always use the most specific
logger, that is the logger in the most specific subclass. For this to work,
the retrieval of a logger
(Logger.getLogger(String))
is done in the constructor of the superclass:
public class Super
{
private static final String loggerName;
protected Logger logger;
public Super(...)
{
LoggerTools.getLogger(this);
}
...
}
Logger for (static) class methods are set directly after the declaration of
the class variable:
private static Logger logger = Logger.getLogger("staticLogger");
Obviously, this joins the logger with the class hierarchy which is done for
easier usage. To further simplify this, the first two prefixes
(de.aristaflow.) are omitted for ADEPT2-logger.
Providing log messages in ADEPT2
ADEPT2 allows to have multiple instances of one component with user-defined
instance names, for instance, a data manager DM1 and a data manager DM2.
If the corresponding data manager class wants to log its specific name, it will
be prepended to every log message:
logger.severe(String.format("'%1$s': Database error.", instanceName));
Logging exceptions in ADEPT2
Log messages should contain much context information to allow for easy tracking
of the source of a log message. The message itself has to be formatted using
String.format(String, Object...).
This eases reading of a message in the source code.
Exception handling generally consists of logging a message and continuing or
rethrowing an exception. Java logging directly supports logging of exceptions
providing the complete stack trace and avoiding messy log messages containing
the stack trace:
try
{
...
}
catch (SQLException sqle)
{
logger.log(Level.SEVERE, "Database Connection failed.", sqle);
}
The logging-output is configured via the boot configuration in
Boot.properties. There are two types of logging-output: console logging
and file logging. Per system (JVM) only one console is allowed but arbitrary log
files. The latter allows for very adjustable logging since every node in the
logger hierarchy can have its own log file - including, of course, the log
messages of the child loggers. The configuration takes the following form:
-
for the console-output
Logging.ConsoleLogger.Root = <name of the node/logger which is the root node
for the logged messages.
DEFAULT: "" (root)>
Logging.ConsoleLogger.Level = <minimal level of the logged messages
DEFAULT: OFF>
(see java.util.logging.Level)
-
for the log files
Logging.Instances.FileLogger = <name or names of the desired file loggers
(comma-separated)>
Logging.FileLogger.LogDirectory = <the directory for the logged files
DEFAULT: 'System.getProperty("user.dir") + "/logs/"'>
Logging.<LoggerName>.Root = <name of the node/logger which is the root
node for the logged messages
DEFAULT: "" (root)>
Logging.<LoggerName>.Level = <minimal level of the logged messages
DEFAULT: OFF>
Logging.<LoggerName>.FileEntries = <amount of bytes in one file
DEFAULT: 20971520 (20 MB)>
Logging.<LoggerName>.FileCount = <number of log files to keep. The current log is always 0. If there are too much files, the oldest one will be deleted.
DEFAULT: 5>
The log files have the same name as their corresponding logger, succeeded by
".log".
Example configuration:
# Boot.properties
# disable console logging
Logging.ConsoleLogger.Level = OFF
# register the file loggers
Logging.Instances.FileLogger = adept2warnings, processmanager
# path to the log directory
Logging.FileLogger.LogDirectory = /var/log/adept2/
# log all log-messages equal to or exceeding log-level WARNING
Logging.adept2warnings.Root = adept2
Logging.adept2warnings.Level = WARNING
# log all log-messages from the process managers, equal to or exceeding log-level INFO
Logging.processmanager.Root = adept2.core.processmanager
Logging.processmanager.Level = INFO