Configuration 如何使用Log4j2将日志输出到JTextArea

Configuration 如何使用Log4j2将日志输出到JTextArea,configuration,log4j,jtextarea,log4j2,appender,Configuration,Log4j,Jtextarea,Log4j2,Appender,几天来,我一直试图将日志输出到JTextArea,但仍然没有成功。基本上,我尝试的是按照现有的appender(如consoleAppender)创建自己的自定义appender,并尝试在log4j2.xml中配置它。我觉得我正朝着正确的方向前进,但不知何故,我无法让它发挥作用。我在log4j2用户邮件列表中询问过,似乎没有人愿意帮助我。希望我能在这里得到帮助。如果您知道如何实现它,请给我一些步骤,甚至代码片段 感谢您在advanced中的帮助 好吧,既然有人否决了我的问题,因为它没有表现出任何

几天来,我一直试图将日志输出到JTextArea,但仍然没有成功。基本上,我尝试的是按照现有的appender(如consoleAppender)创建自己的自定义appender,并尝试在log4j2.xml中配置它。我觉得我正朝着正确的方向前进,但不知何故,我无法让它发挥作用。我在log4j2用户邮件列表中询问过,似乎没有人愿意帮助我。希望我能在这里得到帮助。如果您知道如何实现它,请给我一些步骤,甚至代码片段

感谢您在advanced中的帮助

好吧,既然有人否决了我的问题,因为它没有表现出任何努力,那么我最好拿出一些。我没有展示我所做的任何事情,是因为我不太确定我所做的是正确的方式,人们可能有自己的方法

我面临的问题是,

  • 我找不到将JTextArea对象传递给TextAreaAppender的方法
  • 当我尝试运行测试类时,总是出现一个错误,说TextAreaAppender CLASS_NOT_FOUND,但我已经尝试了所有可能的方法,在log4j2.xml中指定CLASS属性
代码如下:

TextAreaAppender

public class TextAreaAppender extends AbstractOutputStreamAppender<OutputStreamManager>{
    private static TextAreaManagerFactory factory = new TextAreaManagerFactory();

    public enum Target {
        TEXTAREA
    }

    protected TextAreaAppender(String name, Layout<? extends Serializable> layout, Filter filter,
            OutputStreamManager manager, boolean ignoreExceptions) {
        super(name, layout, filter, ignoreExceptions, true, manager);
        // TODO Auto-generated constructor stub
    }

    @PluginFactory
    public static TextAreaAppender createAppender(
            @PluginElement("Layout") Layout<? extends Serializable> layout,
            @PluginElement("Filters") final Filter filter,
            @PluginAttribute("target") final String t,
            @PluginAttribute("name") final String name,
            @PluginAttribute("follow") final String follow,
            @PluginAttribute("ignoreExceptions") final String ignore) {
        if (name == null) {
            LOGGER.error("No name provided for TextAreaAppender");
            return null;
        }
        if (layout == null) {
            layout = PatternLayout.createLayout(null, null, null, null, null, null);
        }
        final boolean isFollow = Boolean.parseBoolean(follow);
        final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
        final Target target = t == null ? Target.TEXTAREA : Target.valueOf(t);
        return new TextAreaAppender(name, layout, filter, getManager(isFollow, target, layout), ignoreExceptions);
    }

    private static OutputStreamManager getManager(final boolean follow, final Target target, final Layout<? extends Serializable> layout) {
        final String type = target.name();
        //should change to getOutputStream(JTextArea), 
        //but not sure how I can pass textarea object to this class
        final OutputStream os = getOutputStream(follow, target);
        return OutputStreamManager.getManager(target.name() + "." + follow, new FactoryData(os, type, layout), factory);
    }

    private static OutputStream getOutputStream(JTextArea ta){ 
        return new TextAreaOutputStream(ta); 
    }
    private static class TextAreaOutputStream extends OutputStream {
        private final JTextArea output;
        public TextAreaOutputStream(JTextArea ta){
            this.output = ta; 
        }
        @Override
        public void write(int i) throws IOException{
            output.append(String.valueOf((char) i)); 
        }
    }

    /**
     * Data to pass to factory method.
     */
    private static class FactoryData {
        private final OutputStream os;
        private final String type;
        private final Layout<? extends Serializable> layout;

        /**
         * Constructor.
         * @param os The OutputStream.
         * @param type The name of the target.
         * @param layout A Serializable layout
         */
        public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
            this.os = os;
            this.type = type;
            this.layout = layout;
        }
    }
    /**
     * Factory to create the Appender.
     */
    private static class TextAreaManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {

        /**
         * Create an OutputStreamManager.
         * @param name The name of the entity to manage.
         * @param data The data required to create the entity.
         * @return The OutputStreamManager
         */
        @Override
        public OutputStreamManager createManager(final String name, final FactoryData data) {
            return new TextAreaOutputStreamManager(data.os, data.type, data.layout);// protected constructor???
        }
    }

    private static class TextAreaOutputStreamManager extends OutputStreamManager{

        public TextAreaOutputStreamManager(OutputStream os, String name,
                Layout<?> layout) {
            super(os, name, layout);
            // TODO Auto-generated constructor stub
        }
    }
}
log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
        <TextArea name="TextArea" class="testing.Log4j2Example.TextAreaAppender">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </TextArea>
    </Appenders>
    <Loggers>
        <Logger name="testing.Log4j2Example" level="ALL">
          <AppenderRef ref="TextArea"/>
        </Logger>

        <Root level="ERROR">
            <AppenderRef ref="CONSOLE"/>
        </Root>
    </Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="">
    <Properties>
        <Property name="log-path">log</Property>
    </Properties>
    <Appenders>
        <Console name="console-log" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>
        </Console>
        <JTextAreaAppender name="jtextarea-log" maxLines="100">
            <PatternLayout>
                <pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss} %msg%n</pattern>
            </PatternLayout>
        </JTextAreaAppender>
    </Appenders>
    <Loggers>
        <Logger name="My Logger" level="debug" additivity="false">
            <appender-ref ref="console-log" level="debug"/>
            <appender-ref ref="jtextarea-log" level="debug"/>
        </Logger>
        <Root level="info" additivity="false">
            <AppenderRef ref="console-log"/>
        </Root>
    </Loggers>
</Configuration>


您可以将日志从Log4j输出到一个临时文件或内存缓冲区,并将该文件尾随到JTextArea。我建议您不要直接登录JTextArea。日志记录的级别非常低,这样做会将用户界面元素与业务层和数据库层结合起来,如果您有这些层的话。

请在log4j2.xml中尝试以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="testing.Log4j2Example">
    <Appenders>
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
        <TextArea name="TextArea">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </TextArea>
    </Appenders>
    <Loggers>
        <Logger name="testing.Log4j2Example" level="ALL">
          <AppenderRef ref="TextArea"/>
        </Logger>
        <Root level="ERROR">
            <AppenderRef ref="CONSOLE"/>
        </Root>
    </Loggers>
</Configuration>

我不确定,但我认为在您的文本区域appender类中需要以下行:

@Plugin(name = "TextArea", category = "Core", elementType = "appender", printObject = true)
public class TextAreaAppender extends AbstractOutputStreamAppender<OutputStreamManager>{
....
}
@插件(name=“TextArea”,category=“Core”,elementType=“appender”,printObject=true)
公共类TextAreaAppender扩展了AbstractOutputStreamAppender{
....
}


此设置对我有效:)

以下方法对我有效,我基于
log4j
解决方案,该解决方案提供了有关
log4j2
附加器的其他一般信息

jtextraeaappender.java

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;

import javax.swing.*;
import java.util.ArrayList;

import static javax.swing.SwingUtilities.invokeLater;
import static org.apache.logging.log4j.core.config.Property.EMPTY_ARRAY;
import static org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout;

@Plugin(name = "JTextAreaAppender", category = "Core", elementType = "appender", printObject = true)
public class JTextAreaAppender extends AbstractAppender
{
    private static volatile ArrayList<JTextArea> textAreas = new ArrayList<>();

    private int maxLines;

    private JTextAreaAppender(String name, Layout<?> layout, Filter filter, int maxLines, boolean ignoreExceptions)
    {
        super(name, filter, layout, ignoreExceptions, EMPTY_ARRAY);
        this.maxLines = maxLines;
    }

    @SuppressWarnings("unused")
    @PluginFactory
    public static JTextAreaAppender createAppender(@PluginAttribute("name") String name,
                                                   @PluginAttribute("maxLines") int maxLines,
                                                   @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
                                                   @PluginElement("Layout") Layout<?> layout,
                                                   @PluginElement("Filters") Filter filter)
    {
        if (name == null)
        {
            LOGGER.error("No name provided for JTextAreaAppender");
            return null;
        }

        if (layout == null)
        {
            layout = createDefaultLayout();
        }
        return new JTextAreaAppender(name, layout, filter, maxLines, ignoreExceptions);
    }

    // Add the target JTextArea to be populated and updated by the logging information.
    public static void addLog4j2TextAreaAppender(final JTextArea textArea)
    {
        JTextAreaAppender.textAreas.add(textArea);
    }

    @Override
    public void append(LogEvent event)
    {
        String message = new String(this.getLayout().toByteArray(event));

        // Append formatted message to text area using the Thread.
        try
        {
            invokeLater(() ->
            {
                for (JTextArea textArea : textAreas)
                {
                    try
                    {
                        if (textArea != null)
                        {
                            if (textArea.getText().length() == 0)
                            {
                                textArea.setText(message);
                            } else
                            {
                                textArea.append("\n" + message);
                                if (maxLines > 0 & textArea.getLineCount() > maxLines + 1)
                                {
                                    int endIdx = textArea.getDocument().getText(0, textArea.getDocument().getLength()).indexOf("\n");
                                    textArea.getDocument().remove(0, endIdx + 1);
                                }
                            }
                            String content = textArea.getText();
                            textArea.setText(content.substring(0, content.length() - 1));
                        }
                    } catch (Throwable throwable)
                    {
                        throwable.printStackTrace();
                    }
                }
            });
        } catch (IllegalStateException exception)
        {
            exception.printStackTrace();
        }
    }
}

你说得有道理。谢谢你的建议,我试试看。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="">
    <Properties>
        <Property name="log-path">log</Property>
    </Properties>
    <Appenders>
        <Console name="console-log" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>
        </Console>
        <JTextAreaAppender name="jtextarea-log" maxLines="100">
            <PatternLayout>
                <pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss} %msg%n</pattern>
            </PatternLayout>
        </JTextAreaAppender>
    </Appenders>
    <Loggers>
        <Logger name="My Logger" level="debug" additivity="false">
            <appender-ref ref="console-log" level="debug"/>
            <appender-ref ref="jtextarea-log" level="debug"/>
        </Logger>
        <Root level="info" additivity="false">
            <AppenderRef ref="console-log"/>
        </Root>
    </Loggers>
</Configuration>
protected static Logger logger;

public MyClass() {
      // Setup logger
      logger = LogManager.getLogger("My Logger");

      ...

      // Create logging panel
      JTextArea jLoggingConsole = new JTextArea(5,0); // 5 lines high here
      jLoggingConsole.setLineWrap(true);
      jLoggingConsole.setWrapStyleWord(true);
      jLoggingConsole.setEditable (false);
      jLoggingConsole.setFont(new Font("Courier", Font.PLAIN, 12));

      // Make scrollable console pane
      JScrollPane jConsoleScroll = new JScrollPane(this.jLoggingConsole);
      jConsoleScroll.setVerticalScrollBarPolicy ( ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS );

      // Subscribe the text area to JTextAreaAppender
      JTextAreaAppender.addLog4j2TextAreaAppender(this.jLoggingConsole);

      ...
}