The Logging interface
The Logging interface defines the base support for logging by any class. This interface is implemented by
ObjectTo11. Any class extending ObjectTo11 get the ability to log.
This interface is defined as follows:
package com.xpierre.utils;
/**
This interface describes the list of functions relative to logging
through the Logger class.
*/
public interface Logging
{
/**
Sets the Logger instance
*/
public void setLogger(Logger aLogger);
/**
Returns the logger instance
*/
public Logger getLogger();
/**
Logs a debug message, only if the instance-level severity allows it
*/
public void logDebug(String s);
/**
Logs a info message, only if the instance-level severity allows it
*/
public void logInfo(String s);
/**
Logs a error message, only if the instance-level severity allows it
*/
public void logError(String s);
/**
Logs a critical message, only if the instance-level severity allows it
*/
public void logCritical(String s);
/**
Sets the instance-level minimum logging severity level
*/
public void setMinimumLoggingSeverityLevel(int severity);
}
Basically, 4 levels of logging are supported (debug, info, error and critical). Logging defines the
method you should call to trigger logging of information (logDebug(), logInfo(), …). The object used to
actually write the information is an instance of the Logger class. Logger does NOT implement the Logging
interface. It is a tool to be used by classes that do implement it (because Logger writes to files. You may
want to write in other places).
BaseLoggingImplementation class is provided as a base implementation of the Logging interface.
ObjectTo11 contains an instance of that class to which all Logging methods are proxied.
package com.xpierre.utils;
/**
Base implementation of the Logging interface. Use instances
of this class as proxy to the interface
*/
public class BaseLoggingImplementation implements Logging
{
/**
The instance's logger instance. Create it from above and set
it in the object using setLogger
*/
protected Logger logger = null;
/**
Instance-based minimum logging severity level. This allows you
to bypass the logger's minimum severity level. So, for instance,
if the logger is set to log debug and above, you could
set some instance to overwrite that and log info and above
*/
protected int minimumLoggingSeverityLevel = Logger.SEVERITY_DEBUG;
public void setMinimumLoggingSeverityLevel(int severity) {
minimumLoggingSeverityLevel = severity;
}
public void setLogger(Logger aLogger) {
logger = aLogger;
}
public Logger getLogger() {
return logger;
}
public void logDebug(String s) {
if(logger == null ||
minimumLoggingSeverityLevel > Logger.SEVERITY_DEBUG) {
return;
}
logger.write(s,Logger.SEVERITY_DEBUG);
}
public void logInfo(String s) {
if(logger == null ||
minimumLoggingSeverityLevel > Logger.SEVERITY_INFO) {
return;
}
logger.write(s,Logger.SEVERITY_INFO);
if(logger.getAppendSeverityLevel()) {
logger.write(s,Logger.SEVERITY_DEBUG);
}
}
public void logError(String s) {
if(logger == null ||
minimumLoggingSeverityLevel > Logger.SEVERITY_ERROR) {
return;
}
logger.write(s,Logger.SEVERITY_ERROR);
if(logger.getAppendSeverityLevel()) {
logger.write(s,Logger.SEVERITY_INFO);
logger.write(s,Logger.SEVERITY_DEBUG);
}
}
public void logCritical(String s) {
if(logger == null ||
minimumLoggingSeverityLevel > Logger.SEVERITY_CRITICAL) {
return;
}
logger.write(s,Logger.SEVERITY_CRITICAL);
if(logger.getAppendSeverityLevel()) {
logger.write(s,Logger.SEVERITY_ERROR);
logger.write(s,Logger.SEVERITY_INFO);
logger.write(s,Logger.SEVERITY_DEBUG);
}
}
}
Any class that does not extend ObjectTo11, but wishes to implement Logging, can use an instance of of
BaseLoggingImplementation that proxies the calls.
Something like this can be written:
public class MyClass implements Logging {
public MyClass() {
super();
logging = new BaseLoggingImplementation();
}
protected BaseLoggingImplementation logging = null;
public synchronized void setMinimumLoggingSeverityLevel(int severity) {
logging.setMinimumLoggingSeverityLevel(severity);
}
public synchronized void setLogger(Logger aLogger) {
logging.setLogger(aLogger);
}
public synchronized Logger getLogger() {
return logging.getLogger();
}
public synchronized void logDebug(String s) {
logging.logDebug(s);
}
public synchronized void logInfo(String s) {
logging.logInfo(s);
}
public synchronized void logError(String s) {
logging.logError(s);
}
public synchronized void logCritical(String s) {
logging.logCritical(s);
}
}
The Logger instance must have some entries set in the Properties object it receives. Here’s a sample file:
(1) Logger.Name MyLogger
(2) Logger.Directory d:/logs
(3) Logger.LogfileName MyLogger
(4) Logger.MinimumSeverityLevel debug
(5) Logger.Mail.MailOnDebug no
Logger.Mail.MailOnInfo no
Logger.Mail.MailOnError no
Logger.Mail.MailOnCritical yes
(6) Logger.Mail.Server mail.domain.com
(7) Logger.Mail.From support@domain.com
(8) Logger.Mail.To sysadmin@domain.com
(9) Logger.Mail.MinimumDelayBetweenMails 600
(10) Logger.AppendSecurityLevel yes
(11) Logger.UseDefaultDirectory yes
(1) Name of the Logger, so you know where the messages are coming from
(2) Directory where to place the logfiles into.
(3) The stem-name for the logfile names. To that stem name is appended the severity level and the date
(so, here, MyLogger_debug20000510.log and so on)
(4) The minimum severity level to start logging at. debug, info, error or critical. In development, use
debug, in production, use error
(5) Does the Logger send a mail with the message logged for each severity level?
(6) What mail server it uses to do so
(7) What from tag it uses
(8) Where it is sent to. Several email addresses separated by ‘;’ are accepted
(9) How log it waits between each mailed message (in seconds). If the database is down, every thread is
gonna report critical messages (if you coded it that way), and your mailbox will get flooded. ‘0’ to mail
upon each and every message
(10) When constructing the logfile names, do you append the security level?
(11) When writing to logfiles, do you place them in the directory specified, or in the current directory?
Kinda redundant, but, whatever
Once your application has created a Logger, it can set it in any object that implements Logging. This way,
logging is centralized. It is up to the developer to decide how many Logger instances he creates, and which
instances of what receive each Logger. If you refer to the sql package documentation, you’ll see that the
Logger set in the JdbcConnectionPool instance is handed down to every JdbcConnection it creates.