Lukas Knuth
Lukas Knuth

Reputation: 25755

log4j in a JTextPane

I'm currently trying to make Log4J log into a JTextPane. I want to use a TextPane because I want basic highlighting (e.g. errors are red and infos are green).

I have two loggers set up, one (the root-logger) logs everything into a file and the other (guiLogger) logs only some errors and infos on the GUI in a JTextPane.

The problem I'm currently facing is, that I can't get appending to the TextPane to work. What I currently have looks something like this:

public class Log extends AppenderSkeleton{

    private final JTextPane log;
    private final StyledDocument doc;

    public Log(){
        super();
        log = new JTextPane();
        doc = log.getStyledDocument();
    }

    @Override
    protected void append(LoggingEvent loggingEvent) {
        try {
            doc.insertString(doc.getLength(), "Hello World!", null);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public JTextPane getView(){
        return log;
    }
}

The Log4J config-file looks like this:

# The root-logger should log everything.
log4j.rootLogger = DEBUG, file

# Append the logs to a file.
log4j.appender.file = org.apache.log4j.RollingFileAppender
# [...]

# The logger which logs on the GUI (just some user-information).
log4j.logger.guiLogger = INFO, gui

# Append the logs to the GUI
log4j.appender.gui = mypackage.Log
# Formatting of the output:
log4j.appender.gui.layout = org.apache.log4j.PatternLayout
log4j.appender.gui.layout.ConversionPattern = %m%n

The append()-method gets called, and the insertString()-method performs clean (it does not enter the catch-block), but I don't see any content in the TextPane on the GUI.

What I have tried to fix this:

Since the JTextPane has no fireContentChanged()-method (or similar), I'm kind of lost here.


I have played around a bit more and found some other things:

Also, I checked which thread called the method by adding this to the append()-method body:

System.out.println("Thread: "+Thread.currentThread().getName());

It shows the following if I simply do two log-statements from somewhere in the code:

Thread: AWT-EventQueue-0
Thread: AWT-EventQueue-0

and when I call the append()-method directly from the constructor of the Log-class (plus the two logging-statements from above), it shows the following:

Thread: AWT-EventQueue-0
Thread: AWT-EventQueue-0
Thread: AWT-EventQueue-0

The first call appends the text probably. But the other two don't seam to work.

My GUI is build from the AWT-EventQueue by using SwingUtilities.invokeLater(). The two logging-calls are made in the same context (and therefore come from the EventQueue, too).

Upvotes: 2

Views: 2283

Answers (2)

JB Nizet
JB Nizet

Reputation: 691785

The text pane is private to the appender, and you don't have any getter for it. So I would guess that the GUI has a text pane, and the logger has another text pane it appends to.

That, or you're getting the text pane from a Log instance that is not the same as the Log instance that Log4j instantiates.

Also, the appender might be use by several threads, but the Swing components may only be accessed from the event dispatch thread. Every append to the text pane should be done inside a SwingUtilities.invokeLater() call.

Upvotes: 2

StanislavL
StanislavL

Reputation: 57391

Check whether yu don;t call setText() or setContentType() and may be some more methods which recreate Document. Instead of saving reference to the document get it from pane. Not

doc.insertString(doc.getLength(), "Hello World!", null);

but

log.getStyledDocument().insertString(doc.getLength(), "Hello World!", null);

Upvotes: 1

Related Questions