我一直试图将日志输出到JTextArea几天,但仍然没有运气。基本上我尝试过的是在现有的appender(如consoleAppender)之后创建自己的自定义appender,并尝试在log4j2.xml中配置它。我觉得我正朝着正确的方向前进,但不知怎的,我无法让它发挥作用。我在log4j2用户邮件列表中询问过,似乎没有人关心帮助我。希望我能在这里得到我的帮助。如果您知道如何实现它,请给我步骤甚至代码片段。
感谢您的帮助。
好吧,因为有人下来投了我的问题,因为它没有显示任何努力,所以我最好展示一些。我没有表现出我所做的任何事情,因为我不太确定我所做的是正确的方式,人们可能有自己的方法。
我面临的问题是,
代码如下,
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>
答案 0 :(得分:9)
派对有点晚了,但希望这对那些希望实现与OP相同目标的人有用。以下方法对我有用,我基于log2j解决方案提供了here以及有关log4j2 appenders here的其他一般信息。
<强> JTextAreaAppender.java 强>
import java.util.ArrayList;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
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 org.apache.logging.log4j.core.layout.PatternLayout;
@Plugin(name = "JTextAreaAppender", category = "Core", elementType = "appender", printObject = true)
public class JTextAreaAppender extends AbstractAppender {
private static final long serialVersionUID = 1L;
private static volatile ArrayList<JTextArea> jTextAreaList = new ArrayList<JTextArea>();
private int maxLines = 0;
protected JTextAreaAppender(String name, Layout<?> layout, Filter filter, int maxLines, boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions);
this.maxLines = maxLines;
}
@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 = PatternLayout.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 addTextArea(final JTextArea textArea) {
JTextAreaAppender.jTextAreaList.add(textArea);
}
@Override
public void append(LogEvent event) {
// TODO Auto-generated method stub
final String message = new String(this.getLayout().toByteArray(event));
// Append formatted message to text area using the Thread.
try {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (JTextArea jTA : jTextAreaList){
try {
if (jTA != null) {
if (jTA.getText().length() == 0) {
jTA.setText(message);
} else {
jTA.append("\n" + message);
if (maxLines > 0 & jTA.getLineCount() > maxLines + 1) {
int endIdx = jTA.getDocument().getText(0, jTA.getDocument().getLength()).indexOf("\n", 0);
jTA.getDocument().remove(0, endIdx+1);
}
}
String content = jTA.getText();
jTA.setText(content.substring(0,content.length()-1));
}
} catch (final Throwable t) {
System.out.println("Unable to append log to text area: "
+ t.getMessage());
}
}
}
});
} catch (final IllegalStateException e) {
// ignore case when the platform hasn't yet been iniitialized
}
}
}
确保在 log4j2.xml 中的 Configuration 下设置JTextAreaAppender的包。
<强> log4j2.xml 强>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="package of JTextAreaAppender">
<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.addTextArea(this.jLoggingConsole);
...
}
答案 1 :(得分:1)
您可以将Log4j中的日志输出到临时文件或内存缓冲区,并将此文件拖放到JTextArea中。我建议你不要直接登录JTextArea。日志记录的级别非常低,如果您有这样的图层,这样做会将您的用户界面元素与业务和数据库层结合起来。
答案 2 :(得分:0)
在 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>
我不确定,但我认为 TextAreaAppender 类需要以下行:
@Plugin(name = "TextArea", category = "Core", elementType = "appender", printObject = true)
public class TextAreaAppender extends AbstractOutputStreamAppender<OutputStreamManager>{
....
}
这个设置对我有用:)