在JavaFX中将SLF4J日志重定向到TextArea

我想在JavaFX中的TextArea中显示SLF4J记录的错误。 到目前为止我所拥有的是logback-test.xml中的一个appender

    %-4relative [%thread] %-5level %logger{35} - %msg%n   

TextArea准备好接收流:

 public class Output extends OutputStream{ private final TextArea ta; public Output(TextArea ta) { this.ta = ta; } @Override public void write(int b) throws IOException { if (ta!=null) { ta.appendText(String.valueOf((char) b)); } } } 

和一个处理追加的类:

 public class AppTA extends AppenderBase { PatternLayoutEncoder encoder; OutputStream os; @Override protected void append(ILoggingEvent event) { try { if (isEncoderInitialized) { this.encoder.doEncode(event); } } catch (IOException e) { } } @Override public void start() { if (this.encoder == null) { addError("No encoder set for the appender named [" + name + "]."); return; } try { encoder.init(os); } catch (IOException ex) { Logger.getLogger(AppTA.class.getName()).log(Level.SEVERE, null, ex); } super.start(); } public PatternLayoutEncoder getEncoder() { return encoder; } public void setEncoder(PatternLayoutEncoder encoder) { this.encoder = encoder; } } 

现在我遇到的问题是我的TextArea在控制器类中,我不知道如何将它们链接在一起。 特别是当SLF4J自己创建AppTA实例时 – 我真的没办法将TextArea传递给AppTA使用的AppTA

我怎么解决这个问题?

这个答案取决于您的基础日志框架是否为logback。 由于SLF4J一次只支持一个日志记录实现,因此我认为不可能以与实现无关的方式解决。

解决此问题的最简单方法是创建自己的appender并利用静态,以便可以跨应用程序访问流。
下面我演示一个appender的基本示例,它可以随时静态设置其输出流。
这有一些局限性,主要是它一次只能处理一个输出流,因此不应该太难以扩展以支持多个输出流。

在下面的应用程序中,当您单击日志按钮时,它将记录信息和错误消息,所有输出将转到标准输出,但只有错误消息将显示在文本区域中。

基本JavaFx应用程序类

 public class Main extends Application { private static final Logger LOG = LoggerFactory.getLogger(Main.class); public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Button btn = new Button(); btn.setText("Log stuff"); btn.setOnAction(a-> { LOG.info("This is some info"); LOG.error("This is some error"); }); TextArea textArea = new TextArea(); OutputStream os = new TextAreaOutputStream(textArea); MyStaticOutputStreamAppender.setStaticOutputStream(os); GridPane grid = new GridPane(); grid.add(textArea, 0 ,0); grid.add(btn, 0, 1); primaryStage.setScene(new Scene(grid, 500, 250)); primaryStage.show(); } private static class TextAreaOutputStream extends OutputStream { private TextArea textArea; public TextAreaOutputStream(TextArea textArea) { this.textArea = textArea; } @Override public void write(int b) throws IOException { textArea.appendText(String.valueOf((char) b)); } } } 

简单的自定义appender类

 public class MyStaticOutputStreamAppender extends OutputStreamAppender { private static final DelegatingOutputStream DELEGATING_OUTPUT_STREAM = new DelegatingOutputStream(null); @Override public void start() { setOutputStream(DELEGATING_OUTPUT_STREAM); super.start(); } public static void setStaticOutputStream(OutputStream outputStream) { DELEGATING_OUTPUT_STREAM.setOutputStream(outputStream); } private static class DelegatingOutputStream extends FilterOutputStream { /** * Creates a delegating outputstream with a NO-OP delegate */ public DelegatingOutputStream(OutputStream out){ super(new OutputStream() { @Override public void write(int b) throws IOException {} }); } void setOutputStream(OutputStream outputStream) { this.out = outputStream; } } } 

Logback配置

     %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n     ERROR   %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n        

您可以配置Logback以写入System.out和System.err 。

在应用程序中配置这些流( setOut , setErr )以写入textarea。

此解决方案适用于任何SLF4J绑定,无需更改代码。

基本上你会实现一个只读的JavaFX控制台。

另请查看以下答案: https : //stackoverflow.com/a/9219837/506855