Redirecting SLF4J log to TextArea in JavaFX

前端 未结 2 617
孤街浪徒
孤街浪徒 2021-02-10 04:10

I would like to show errors logged by SLF4J in TextArea in JavaFX. What I have so far is an appender in logback-test.xml:

<         


        
相关标签:
2条回答
  • 2021-02-10 05:11

    You could configure Logback to write to System.out and System.err.

    Configure those streams (setOut, setErr) in your application to write to the textarea.

    This solution should work with any SLF4J binding without code changes.

    Basically you would implement a read-only JavaFX console.

    Also have a look at the following answer: https://stackoverflow.com/a/9219837/506855

    0 讨论(0)
  • 2021-02-10 05:12

    This answer is dependent on your underlying logging framework being logback. Since SLF4J only supports one logging implementation at a time I don't think its possible to solve in an implementation agnostic way.

    The simplest way to solve this issue is to create your own appender and utilize static state so you can access the streams across the application.
    Below I demonstrate a basic example of an appender that can have its output stream set statically at any time.
    This has some limitations, mainly that it can only handle one outputstream at a time, bu tit shouldn't be too difficult to extend to support multiple.

    In the below application when you click the log button it will log info and error messages, all output will go to stdout but only error messsages will be shown in the text area.

    Basic JavaFx application class

    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));
            }
        }
    }
    

    Simple custom appender class

    public class MyStaticOutputStreamAppender<E> extends OutputStreamAppender<E> {
    
    
        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 config

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <appender name="MyCustomAppender" class="example.MyStaticOutputStreamAppender">
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
            </filter>
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <root>
            <appender-ref ref="STDOUT" />
            <appender-ref ref="MyCustomAppender" />
        </root>
    
    </configuration>
    
    0 讨论(0)
提交回复
热议问题