I have been trying to output logs to a JTextArea for days and still no luck. Basically what I have tried is creating my own custom appender following existing appender like consoleAppender and tried to configure it in log4j2.xml. I feel I am heading the right direction but somehow I couldn't get it to work. I have asked in log4j2 user mailing list and no one seems to care to help me. Hopefully I can get my help here. If you know how to achieve it, please give me steps or even code snippets.
Thank you for your help in advanced.
Okay, since someone down voted my question as it doesn't show any effort then I'd better show some. I didn't show anything I have done was because I am not so sure what I was doing was the correct way and people might have their own approach.
the problems I am facing are,
- I cannot find a way to pass that JTextArea object to my TextAreaAppender
- When I tried to run the test classes, always getting an error saying TextAreaAppender CLASS_NOT_FOUND, but I have tried all the possible way I can find to specify the class attribute in log4j2.xml
codes are as following,
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 test class
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>