在JavaFX中将SLF4J日志重定向到TextArea [英] Redirecting SLF4J log to TextArea in JavaFX

查看:1904
本文介绍了在JavaFX中将SLF4J日志重定向到TextArea的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在JavaFX中显示SLF4J在 TextArea 中记录的错误。到目前为止, logback-test.xml 中的 appender

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:

<appender name="err" class="logtest.AppTA">
    <filter class="logtest.ErrFilter" />
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
</appender>

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<ILoggingEvent> {

    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 由记录器使用。

Now the problem I'm having is that my TextArea is in the controller class and I don't know how to link them together. Especially when SLF4J creates AppTA instance on its own - I don't really have a way to pass my TextArea to AppTA used by logger.

我该如何解决这个问题?

How can I tackle this?

推荐答案

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

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.

解决这个问题的最简单方法问题是创建自己的appender并利用静态状态,以便可以跨应用程序访问流。

下面我演示一个appender的基本示例,可以随时静态设置其输出流。 br>
这有一些限制,主要是它一次只能处理一个输出流,不应该太难以扩展以支持多个输出流。

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.

基本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 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>

这篇关于在JavaFX中将SLF4J日志重定向到TextArea的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆