Java 将log4j2输出附加到TextArea

Java 将log4j2输出附加到TextArea,java,log4j2,Java,Log4j2,我正在log4j2中搜索一个简单的方法,将日志附加到文本区域 在log4j中,这可以通过扩展AppenderSkleton类实现,但在log4j2中找不到类似的机制 此外,使用 System.setOut(myPrintStream); 也不行 是否有可能将此功能与log4j2一起使用?看起来您正在尝试执行类似的操作: 那张Jira票有部分解决方案。您可以查看ConsoleAppender的代码,了解如何创建自定义appender 您可以在log4j2.xml中配置自定义appender,就像

我正在log4j2中搜索一个简单的方法,将日志附加到文本区域

在log4j中,这可以通过扩展AppenderSkleton类实现,但在log4j2中找不到类似的机制

此外,使用

System.setOut(myPrintStream);
也不行


是否有可能将此功能与log4j2一起使用?

看起来您正在尝试执行类似的操作:

那张Jira票有部分解决方案。您可以查看ConsoleAppender的代码,了解如何创建自定义appender


您可以在log4j2.xml中配置自定义appender,就像配置内置appender一样,但您需要在配置元素的packages属性中指定插件的包(以便log4j2 PluginManager可以找到您的插件。)

看起来您正在尝试执行类似的操作:

那张Jira票有部分解决方案。您可以查看ConsoleAppender的代码,了解如何创建自定义appender


您可以在log4j2.xml中配置自定义appender,就像配置内置appender一样,但是您需要在配置元素的packages属性中指定插件的包(这样log4j2 PluginManager就可以找到您的插件。)

回答晚了,但我终于找到了解决问题的方法。 要将log4j2控制台流附加到JavaFXTextArea,可以使用ListView或类似控件,甚至swing控件。我的解决方案还将standard System.out附加到logger视图。看看你自己

首先,我通过屏幕截图向您展示了我当前的结果(很抱歉,我不能直接将其包括在这里,因为我在stackoverflow的用户帐户没有足够的信誉…):

步骤1:编辑log4j2.xml文件并添加属性follow=“true”:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
    <Console name="STDOUT" target="SYSTEM_OUT" follow="true">
        <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
    </Console>
</Appenders>
<Loggers>
    <Root level="DEBUG">
        <AppenderRef ref="STDOUT" />
    </Root>
</Loggers>
</Configuration>
另一个问题:彩色字符串格式应该重新编码,并对日志消息类型(信息、调试、跟踪等)进行更好的检测。使用诸如“text.toString().contains(“TRACE”))之类的东西进行过滤真的很难看


如果您对此有任何问题,请告诉我。这个帖子真的很旧,但如果你在这里写,我会收到一封电子邮件。然后我可以直接回答你

一个迟来的答案,但我最终找到了解决问题的办法。 要将log4j2控制台流附加到JavaFXTextArea,可以使用ListView或类似控件,甚至swing控件。我的解决方案还将standard System.out附加到logger视图。看看你自己

首先,我通过屏幕截图向您展示了我当前的结果(很抱歉,我不能直接将其包括在这里,因为我在stackoverflow的用户帐户没有足够的信誉…):

步骤1:编辑log4j2.xml文件并添加属性follow=“true”:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
    <Console name="STDOUT" target="SYSTEM_OUT" follow="true">
        <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" />
    </Console>
</Appenders>
<Loggers>
    <Root level="DEBUG">
        <AppenderRef ref="STDOUT" />
    </Root>
</Loggers>
</Configuration>
另一个问题:彩色字符串格式应该重新编码,并对日志消息类型(信息、调试、跟踪等)进行更好的检测。使用诸如“text.toString().contains(“TRACE”))之类的东西进行过滤真的很难看

如果您对此有任何问题,请告诉我。这个帖子真的很旧,但如果你在这里写,我会收到一封电子邮件。然后我可以直接回答你

看起来像
package tuc.plentyfx.configurator.views;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.ToggleButton;
import javafx.util.Callback;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;

import tuc.plentyfx.common.LogStringCell;

public class LoggerConsoleController {
    static final Logger logger = LogManager.getLogger(LoggerConsoleController.class.getName());

    @FXML
    private ListView<String> listViewLog;

    @FXML
    private ToggleButton toggleButtonAutoScroll;

    @FXML
    private ChoiceBox<Level> choiceBoxLogLevel;

    @FXML
    void handleRemoveSelected() {
        listViewLog.getItems().removeAll(listViewLog.getSelectionModel().getSelectedItems());
    }

    @FXML
    void handleClearLog() {
        listViewLog.getItems().clear();
    }

    @FXML
    void initialize() {
        listViewLog.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
        Configuration loggerConfiguration = loggerContext.getConfiguration();
        LoggerConfig loggerConfig = loggerConfiguration.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
        /* ChoiceBox füllen */
        for (Level level : Level.values()) {
            choiceBoxLogLevel.getItems().add(level);
        }
        /* Aktuellen LogLevel in der ChoiceBox als Auswahl setzen */
        choiceBoxLogLevel.getSelectionModel().select(loggerConfig.getLevel());
        choiceBoxLogLevel.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Level>() {
            @Override
            public void changed(ObservableValue<? extends Level> arg0, Level oldLevel, Level newLevel) {
                loggerConfig.setLevel(newLevel);
                loggerContext.updateLoggers(); // übernehme aktuellen LogLevel
            }
        });

        listViewLog.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> listView) {
                return new LogStringCell();
            }
        });

        /* den Origial System.out Stream in die ListView umleiten */
        PipedOutputStream pOut = new PipedOutputStream();
        System.setOut(new PrintStream(pOut));
        PipedInputStream pIn = null;
        try {
            pIn = new PipedInputStream(pOut);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(new InputStreamReader(pIn));

        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (!isCancelled()) {
                    try {
                        String line = reader.readLine();
                        if (line != null) {
                            Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    listViewLog.getItems().add(line);

                                    /* Auto-Scroll + Select */
                                    if (toggleButtonAutoScroll.selectedProperty().get()) {
                                        listViewLog.scrollTo(listViewLog.getItems().size() - 1);
                                        listViewLog.getSelectionModel().select(listViewLog.getItems().size() - 1);
                                    }
                                }
                            });
                        }
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        };
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }
}
package tuc.plentyfx.common;

import javafx.scene.control.ListCell;
import javafx.scene.layout.FlowPane;
import javafx.scene.text.Text;

public class LogStringCell extends ListCell<String> {

    @Override
    protected void updateItem(String string, boolean empty) {
        super.updateItem(string, empty);
        if (string != null && !isEmpty()) {
            setGraphic(createAssembledFlowPane(string));
        }
        else {
            setGraphic(null);
            setText(null);
        }
    }

    /* Erzeuge ein FlowPane mit gefüllten Textbausteien */
    private FlowPane createAssembledFlowPane(String... messageTokens) {
        FlowPane flow = new FlowPane();
        for (String token : messageTokens) {
            Text text = new Text(token);

            if (text.toString().contains(" TRACE ")) {
                text.setStyle("-fx-fill: #0000FF");
            }
            if (text.toString().contains(" ALL ")) {
                text.setStyle("-fx-fill: #FF00FF");
            }
            if (text.toString().contains(" ERROR ")) {
                text.setStyle("-fx-fill: #FF8080");
            }
            if (text.toString().contains(" INFO ")) {
                text.setStyle("-fx-fill: #000000");
            }
            if (text.toString().contains(" FATAL ")) {
                text.setStyle("-fx-fill: #FF0000");
            }
            if (text.toString().contains(" DEBUG ")) {
                text.setStyle("-fx-fill: #808080");
            }
            if (text.toString().contains(" OFF ")) {
                text.setStyle("-fx-fill: #8040FF");
            }
            if (text.toString().contains(" WARN ")) {
                text.setStyle("-fx-fill: #FF8000");
            }

            flow.getChildren().add(text);
        }
        return flow;
    }
}
package application.common;

import java.io.InputStream;
import java.io.OutputStream;

public class SyncPipe implements Runnable {

    private final OutputStream outputStream;
    private final InputStream inputStream;

    public SyncPipe(InputStream inputStream, OutputStream outputStream) {
        this.inputStream = inputStream;
        this.outputStream = outputStream;
    }

    @Override
    public void run() {
        try {
            final byte[] buffer = new byte[1024];
            for (int length = 0; (length = inputStream.read(buffer)) != -1;) {
                outputStream.write(buffer, 0, length);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}