Nearly all projects need to log something. You can use System.out.println(String) for that. But if you want to write the message to a file later you have to change all the logging statements in your code.
So it is recommended to use at least the Logger provided by the jdk:
java.util.logging.Logger
Other projects for logging exist e.g. the popular log4j. But this library is complex and the jar file is too big for my purposes.
Today I discovered slf4j, which is small (<25KB) and provides wrappers for the jdk-Logger and log4j. The nice thing about this library is that you can simply put the jar files into the classpath and slf4j will use e.g. the jdk-Logger. I like it more than the jdk-Logger because slf4j offers a nice interface for logging (the methods are easier to use) e.g.:
- info(String)
- info(String, Throwable)
- warn(String)
- warn(String, Throwable)
- error(String)
- error(String, Throwable)
But all logger don’t have a feature to log directly to the user. So I implemented a Handler that prints a JDialog with the message and the full stack trace. The stack trace will be available if the user clicks on the details button.
/* * This file is part of the timefinder project. * Visit http://www.timefinder.de for more information. * Copyright (C) 2008 Peter Karich. * * This project is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This project is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this project; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * or look at http://www.gnu.org */ package de.timefinder.framework; import java.awt.BorderLayout; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import javax.swing.Icon; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.UIManager; /** * This class provides a Log Handler to be publish directly to the user via * a JDialog, which offers a details Button. * * @author Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net */ public class SwingHandler extends Handler { @Override public void publish(LogRecord record) { if (!isLoggable(record)) { return; } int level = record.getLevel().intValue(); int jOptLevel; if (level >= Level.SEVERE.intValue()) { jOptLevel = JOptionPane.ERROR_MESSAGE; } else if (level >= Level.WARNING.intValue()) { jOptLevel = JOptionPane.WARNING_MESSAGE; } else { jOptLevel = JOptionPane.INFORMATION_MESSAGE; } logIntoDialog(jOptLevel, record.getMessage(), record.getThrown()); } @Override public void flush() { } @Override public void close() throws SecurityException { } private static void logIntoDialog(final int messageLevel, final String errorMessage, final Throwable th) { if (!SwingUtilities.isEventDispatchThread()) { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { logIntoDialog(messageLevel, errorMessage, th); } }); } catch (Exception ex) { JOptionPane.showConfirmDialog(null, errorMessage); } return; } StringBuilder sb = new StringBuilder(); sb.append(errorMessage); if (errorMessage == null || errorMessage.length() == 0) { if (th != null) { sb.append(th.getClass().getName()); sb.append(": "); } // TODO I18N sb.append("Error-Message Not Available>"); } String newErrMessage = sb.toString(); if (th != null) { TFFormatter.printReason(sb, th); } JScrollPane scroll = new JScrollPane(new JTextArea(sb.toString(), 20, 40)); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JTextField(newErrMessage), BorderLayout.CENTER); panel.add(scroll, BorderLayout.SOUTH); // TODO I18N Object[] options = {"Okay", "Details"}; int n = JOptionPane.NO_OPTION; Icon icon; switch (messageLevel) { case JOptionPane.WARNING_MESSAGE: icon = UIManager.getIcon("OptionPane.warningIcon");//NO I18N break; case JOptionPane.ERROR_MESSAGE: icon = UIManager.getIcon("OptionPane.errorIcon");//NO I18N break; case JOptionPane.INFORMATION_MESSAGE: icon = UIManager.getIcon("OptionPane.informationIcon");//NO I18N break; default: icon = UIManager.getIcon("OptionPane.questionIcon");//NO I18N } boolean visible = false; //Switch between Details and No-Details: while (n != JOptionPane.YES_OPTION) { scroll.setVisible(visible); panel.revalidate(); n = JOptionPane.showOptionDialog( null, panel, newErrMessage, JOptionPane.YES_NO_OPTION, messageLevel, icon, options, options[0]); visible = !visible; } } }