I am currently working on a new version of my application, and I just finished rebuilding the log part. It works well but I am skeptical about the choices I made. I am a student and I work alone in some side projects, and I am afraid of developing bad habits.
I use java.util.logging, because it is simple enough for what I need to do.
The logger will be used by several part of the application (but not at the same time). Each executable will have a logging file. All configurations are stored in Settings
class.
Main class :
public class MyLogger
{
public static Logger LOGGER = null; // Logger use by Spider, Cleaner, Checker
private static Handler logFile = null; // Logger file
/**
* Initialize logger before first use
*
* @param folderName sub-folder after the log folder
* @param fileName log file name (without extension)
*/
public static void initLogger(String folderName, String fileName)
{
if (MyLogger.LOGGER != null)
throw new IllegalStateException("Logger already instantiated");
MyLogger.LOGGER = Logger.getLogger(MyLogger.class.getName());
// Check if log is not disable
if (Settings.getProp().getLogLevel() != Level.OFF)
{
String folderPath = Settings.getProp().getLogPath() + folderName;
File dir = new File(folderPath);
// if the directory does not exist, create it (recursively)
if (!dir.exists())
{
try
{
dir.mkdirs();
}
catch (SecurityException e)
{
e.printStackTrace(); // Throw RunTime instead ?
}
}
try
{
// Open log file
MyLogger.logFile = new FileHandler(folderPath + File.separator + fileName + ".log", true);
MyLogger.logFile.setEncoding("UTF-8");
// Attache file to logger
MyLogger.LOGGER.addHandler(MyLogger.logFile);
}
catch (SecurityException | IOException e)
{
e.printStackTrace(); // Throw RunTime instead ?
}
}
LOGGER.setLevel(Settings.getProp().getLogLevel());
// Console Text formatter
LOGGER.setUseParentHandlers(false);
MyConsoleHandler handler = new MyConsoleHandler();
handler.setLevel(Settings.getProp().getConsoleLevel());
handler.setFormatter(new MyFormatter());
LOGGER.addHandler(handler);
LOGGER.config("Logger Started : " + folderName + " - " + fileName);
LOGGER.config(Settings.getProp().toString()); // Print application settings
}
}
Formatter :
public class MyFormatter extends Formatter
{
// Create a DateFormat to format the logger timestamp.
private static final DateFormat df = new SimpleDateFormat("H:mm:ss.SSS");
/* (non-Javadoc)
* @see java.util.logging.Formatter#format(java.util.logging.LogRecord)
*/
@Override
public String format(LogRecord record)
{
StringBuilder builder = new StringBuilder(1000);
builder.append(df.format(new Date(record.getMillis()))).append(" "); // time
builder.append("(").append(record.getThreadID()).append(") "); // Thread ID
builder.append("[").append(record.getLevel()).append("] "); // level
builder.append(formatMessage(record)); // message
builder.append("\n");
return builder.toString();
}
}
Console Handler :
public class MyConsoleHandler extends ConsoleHandler
{
/* (non-Javadoc)
* @see java.util.logging.Handler#publish(java.util.logging.LogRecord)
*/
@Override
public void publish(LogRecord record)
{
try
{
if(record.getLevel().intValue() >= this.getLevel().intValue())
{
String message = getFormatter().format(record);
if (record.getLevel().intValue() >= Level.WARNING.intValue())
{
System.err.write(message.getBytes());
}
else
{
System.out.write(message.getBytes());
}
}
} catch (Exception exception)
{
reportError(null, exception, ErrorManager.FORMAT_FAILURE);
return;
}
}
}
Example of use :
public static void main(String[] args)
{
MyLogger.initLogger("test", "001");
MyLogger.LOGGER.info("Testing message");
MyLogger.LOGGER.warning("A warning message !");
}
Example of output (console) :
22:43:26.918 (1) [CONFIG] Logger Started : test - 001
22:43:26.921 (1) [CONFIG] Appication Settings :
- [...]
- Console Level : CONFIG
- Log Level : FINER
- Log Path : ./log/
- [...]
- OutputQueueLimit : 1000 items
22:43:26.922 (1) [INFO] Testing message
22:43:26.922 (1) [WARNING] A warning message !