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

标签 configuration log4j jtextarea log4j2 appender

我一直在尝试将日志输出到JTextArea几天,但仍然没有运气。基本上,我尝试的是在现有的添加程序(例如consoleAppender)之后创建自己的自定义添加程序,并尝试在log4j2.xml中对其进行配置。我觉得自己正在朝着正确的方向前进,但是不知何故我无法使它正常工作。我在log4j2用户邮件列表中询问过,似乎没人在乎帮助我。希望我能在这里得到帮助。如果您知道如何实现,请给我一些步骤,甚至编写代码段。

感谢您对高级的帮助。

好的,既然有人不赞成我的问题,因为它没有显示任何努力,那么我最好显示一些。我没有做任何事情是因为我不确定我在做什么是正确的方法,人们可能会有自己的方法。

我面临的问题是

  • 我找不到将JTextArea对象传递给我的TextAreaAppender
  • 的方法
  • 当我尝试运行测试类时,总是收到一条错误消息,说TextAreaAppender CLASS_NOT_FOUND,但是我尝试了所有可能的方法,可以在log4j2.xml中找到指定类属性。

  • 代码如下

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

    UI测试类
    public class Log4j2Example {
        class LogModel extends AbstractTableModel{
    
            @Override
            public int getColumnCount() {
                // TODO Auto-generated method stub
                return 1;
            }
    
            @Override
            public int getRowCount() {
                // TODO Auto-generated method stub
                return 0;
            }
    
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                // TODO Auto-generated method stub
                switch(columnIndex){
                    case 0: return null;
                    default: return null;
                }
            }
    
        }
        private final static JTextArea textarea = new JTextArea();
        private final LogModel model = new LogModel();
        private final JTable table = new JTable(model);
        static Log4j2Example INSTANCE = new Log4j2Example();
        JFrame frame = new JFrame();
    
        void run(){
            frame.setLayout(new BorderLayout());
            table.setBorder(new TitledBorder("Table"));
            textarea.setBorder(new TitledBorder("Text Area"));
            textarea.setPreferredSize(new Dimension(100, 150));
            textarea.setEditable(false);
    
            frame.add(table);
            frame.add(textarea, BorderLayout.SOUTH);
    
            frame.setVisible(true);
            frame.setSize(400, 400);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        static final Logger logger = LogManager.getLogger(Log4j2Example.class.getName());
        public static void main(String[] args) {
            INSTANCE.run();
            System.out.println("test");
            logger.trace("Entering Log4j Example.");
            Hello hello = new Hello();
            if (!hello.callMe()) {
                logger.error("Ohh!Failed!");
            }
            logger.trace("Exiting Log4j Example.");
    
    
        }
    }
    

    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>
    

    最佳答案

    以下方法对我有用,我已基于log4j解决方案向here提供了有关log4j2附加程序here的其他常规信息。

    JTextAreaAppender.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();
            }
        }
    }
    

    log4j2.xml
    <?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>
    

    将以下行添加到定义GUI的应用程序代码中,在此示例中,将其添加到类MyClass的构造函数中:
    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);
    
          ...
    }
    

    关于configuration - 如何使用Log4j2将日志输出到JTextArea,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24005748/

    相关文章:

    java - 调整 JTextArea 的大小

    java - Hibernate 注释与集合

    javascript - 如何使用 Webpack 2 将 'require' 或 'import' 插入 js 文件中?

    java - 无法更改 Java 中 JTextArea 中的文本

    java - Java JTextArea 中选择文本触发的哪个事件?

    java - Log4j Windows 事件查看器日志记录

    configuration - 在文件或数据库中配置?

    wcf - 超时 WCF 服务

    java.io.FileNotFoundException some_path XXXXX(文件名、目录名或卷标语法不正确)

    java - Log4j 配置并观察无法正常工作