I need to hack up a small tool. It should read a couple of files and convert them. Right now that works in my IDE. For the user, I'd like to add a small UI which simply shows the log output.
Do you know of a ready-to-use Swing appender for logback? Or something which redirects System.out to a little UI with nothing more than a text field and a "Close" button?
PS: I'm not looking for Chainsaw or Jigsaw or Lilith. I want the display of the log messages in the application, please.
You need to write a custom appender class like so:
public class MyConsoleAppender extends AppenderBase<ILoggingEvent> {
private Encoder<ILoggingEvent> encoder = new EchoEncoder<ILoggingEvent>();
private ByteArrayOutputStream out = new ByteArrayOutputStream();
public MyConsoleAppender() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
setContext(lc);
start();
lc.getLogger("ROOT").addAppender(this);
}
@Override
public void start() {
try {
encoder.init(out);
} catch (IOException e) {}
super.start();
}
@Override
public void append(ILoggingEvent event) {
try {
encoder.doEncode(event);
out.flush();
String line = out.toString(); // TODO: append _line_ to your JTextPane
out.reset();
} catch (IOException e) {}
}
}
You can replace the EchoEncoder with a PatternLayoutEncoder (see CountingConsoleAppender example in the logback examples folder).
The encoder will write each event to a byte buffer, which you can then extract a string and write this to your JTextPane or JTextArea, or whatever you want.
I often rely on JTextArea#append()
, as suggested in this example. Unlike most of Swing, the method happens to be thread safe.
Addendum: Console
is a related example that redirects System.out
and System.err
to a JTextArea
.
No warranty, but here's a sample that I just wrote:
/**
* A Logback appender that appends messages to a {@link JTextArea}.
* @author David Tombs
*/
public class JTextAreaAppender extends AppenderBase<ILoggingEvent>
{
private final JTextArea fTextArea;
private final PatternLayout fPatternLayout;
public JTextAreaAppender(final Context loggerContext, final JTextArea textArea)
{
fTextArea = textArea;
// Log the date, level, class name (no package), and the message.
fPatternLayout = new PatternLayout();
fPatternLayout.setPattern("%d{HH:mm:ss.SSS} %-5level - %msg");
fPatternLayout.setContext(loggerContext);
fPatternLayout.start();
// Make sure not to call any subclass methods right now.
super.setContext(loggerContext);
}
@Override
protected void append(final ILoggingEvent eventObject)
{
// Actual appending must be done from the EDT.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run()
{
final String logStr = fPatternLayout.doLayout(eventObject);
// If the text area already has lines in it, append a newline first.
if (fTextArea.getDocument().getLength() > 0)
{
fTextArea.append("\n" + logStr);
}
else
{
fTextArea.setText(logStr);
}
}
});
}
}