You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-user@logging.apache.org by Alex Wu <al...@gmail.com> on 2014/06/02 09:05:48 UTC

Issue of creating and configuring custom appenders

Hi all, I have followed Ralph's suggestion in this issue and the source
code of ConsoleAppender from apache to tried to create a custom appender
for appending logs to a JTextArea.

https://issues.apache.org/jira/browse/LOG4J2-303

But I am having trouble to make it to work, could anyone please give me
some help for this?

the problems I am facing are,

- I cannot find a way to pass that JTextArea object to my TextAreaAppender
- I am also having problem creating the manager, in ConsoleAppender, they
use "new OutputStreamManager(data.os, data.type, data.layout)", and it's
actually a "protected" constructor, how is this possible? BTW, eclipse is
also showing error about this. *Actually, I got around with this by
creating a subclass of OutputStreamManager in my test and make the
constructor public, not sure if I have done it in a right way though.*

Any help would be appreciated.

Test classes are as follow,

*TextAreaAppender.java*

package testing;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;

import javax.swing.JTextArea;

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.appender.OutputStreamManager;
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.helpers.Booleans;
import org.apache.logging.log4j.core.layout.PatternLayout;

import testing.ConsoleAppender.ConsoleManagerFactory;


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 OutputStreamManager(data.os, data.type,
data.layout);// protected constructor???
        }
    }
}

*Lo4gj2Example.java*

package testing;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.IOException;
import java.io.OutputStream;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
import javax.swing.table.AbstractTableModel;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
import org.apache.logging.log4j.core.appender.OutputStreamManager;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;

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 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) {
logger.trace("Entering Log4j Example.");
Hello hello = new Hello();
if (!hello.callMe()) {
logger.error("Ohh!Failed!");
}
logger.trace("Exiting Log4j Example.");
 INSTANCE.run();
}
}

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

Re: Issue of creating and configuring custom appenders

Posted by James Hutton <ja...@gmail.com>.
Maybe have the appender be the owner of the jtextarea such that you could
call a gettextarea method when initializing your ui? Or you could buffer
until you call an initialize method with the jtext area.  With the first
one not sure if you can write to the text area if it isn't in a frame, but
I'm not a swing expert.
On Jun 2, 2014 3:06 AM, "Alex Wu" <al...@gmail.com> wrote:

> Hi all, I have followed Ralph's suggestion in this issue and the source
> code of ConsoleAppender from apache to tried to create a custom appender
> for appending logs to a JTextArea.
>
> https://issues.apache.org/jira/browse/LOG4J2-303
>
> But I am having trouble to make it to work, could anyone please give me
> some help for this?
>
> the problems I am facing are,
>
> - I cannot find a way to pass that JTextArea object to my TextAreaAppender
> - I am also having problem creating the manager, in ConsoleAppender, they
> use "new OutputStreamManager(data.os, data.type, data.layout)", and it's
> actually a "protected" constructor, how is this possible? BTW, eclipse is
> also showing error about this. *Actually, I got around with this by
> creating a subclass of OutputStreamManager in my test and make the
> constructor public, not sure if I have done it in a right way though.*
>
> Any help would be appreciated.
>
> Test classes are as follow,
>
> *TextAreaAppender.java*
>
> package testing;
>
> import java.io.IOException;
> import java.io.OutputStream;
> import java.io.Serializable;
>
> import javax.swing.JTextArea;
>
> import org.apache.logging.log4j.core.Filter;
> import org.apache.logging.log4j.core.Layout;
> import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> import org.apache.logging.log4j.core.appender.ManagerFactory;
> import org.apache.logging.log4j.core.appender.OutputStreamManager;
> 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.helpers.Booleans;
> import org.apache.logging.log4j.core.layout.PatternLayout;
>
> import testing.ConsoleAppender.ConsoleManagerFactory;
>
>
> 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 OutputStreamManager(data.os, data.type,
> data.layout);// protected constructor???
>         }
>     }
> }
>
> *Lo4gj2Example.java*
>
> package testing;
>
> import java.awt.BorderLayout;
> import java.awt.Dimension;
> import java.io.IOException;
> import java.io.OutputStream;
>
> import javax.swing.JFrame;
> import javax.swing.JTable;
> import javax.swing.JTextArea;
> import javax.swing.border.TitledBorder;
> import javax.swing.table.AbstractTableModel;
>
> import org.apache.logging.log4j.LogManager;
> import org.apache.logging.log4j.Logger;
> import org.apache.logging.log4j.core.Filter;
> import org.apache.logging.log4j.core.Layout;
> import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> import org.apache.logging.log4j.core.appender.OutputStreamManager;
> import org.apache.logging.log4j.core.config.plugins.Plugin;
> import org.apache.logging.log4j.core.config.plugins.PluginElement;
> import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>
> 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 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) {
> logger.trace("Entering Log4j Example.");
> Hello hello = new Hello();
> if (!hello.callMe()) {
> logger.error("Ohh!Failed!");
> }
> logger.trace("Exiting Log4j Example.");
>  INSTANCE.run();
> }
> }
>
> *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>*
>

Re: Issue of creating and configuring custom appenders

Posted by Matt Sicker <bo...@gmail.com>.
That sounds more like a text editor at that point. Interactive /usr/bin/tail


On 4 June 2014 07:34, James Hutton <ja...@gmail.com> wrote:

> Yeah, ideally there's a limit to the buffer in both choices, however why
> aren't you just logging to a file and using the jtextarea to display the
> file contents? Then you don't have as much a worry about memory usage.
> On Jun 4, 2014 8:27 AM, "Gary Gregory" <ga...@gmail.com> wrote:
>
> > Note that you will shoot yourself in the foot with such an appender by
> > causing memory to be exhausted unless the appender never lets the
> contents
> > of the text area grow beyond some limit.
> >
> > Gary
> >
> >
> > On Mon, Jun 2, 2014 at 3:05 AM, Alex Wu <al...@gmail.com> wrote:
> >
> > > Hi all, I have followed Ralph's suggestion in this issue and the source
> > > code of ConsoleAppender from apache to tried to create a custom
> appender
> > > for appending logs to a JTextArea.
> > >
> > > https://issues.apache.org/jira/browse/LOG4J2-303
> > >
> > > But I am having trouble to make it to work, could anyone please give me
> > > some help for this?
> > >
> > > the problems I am facing are,
> > >
> > > - I cannot find a way to pass that JTextArea object to my
> > TextAreaAppender
> > > - I am also having problem creating the manager, in ConsoleAppender,
> they
> > > use "new OutputStreamManager(data.os, data.type, data.layout)", and
> it's
> > > actually a "protected" constructor, how is this possible? BTW, eclipse
> is
> > > also showing error about this. *Actually, I got around with this by
> > > creating a subclass of OutputStreamManager in my test and make the
> > > constructor public, not sure if I have done it in a right way though.*
> > >
> > > Any help would be appreciated.
> > >
> > > Test classes are as follow,
> > >
> > > *TextAreaAppender.java*
> > >
> > > package testing;
> > >
> > > import java.io.IOException;
> > > import java.io.OutputStream;
> > > import java.io.Serializable;
> > >
> > > import javax.swing.JTextArea;
> > >
> > > import org.apache.logging.log4j.core.Filter;
> > > import org.apache.logging.log4j.core.Layout;
> > > import
> > org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> > > import org.apache.logging.log4j.core.appender.ManagerFactory;
> > > import org.apache.logging.log4j.core.appender.OutputStreamManager;
> > > 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.helpers.Booleans;
> > > import org.apache.logging.log4j.core.layout.PatternLayout;
> > >
> > > import testing.ConsoleAppender.ConsoleManagerFactory;
> > >
> > >
> > > 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 OutputStreamManager(data.os, data.type,
> > > data.layout);// protected constructor???
> > >         }
> > >     }
> > > }
> > >
> > > *Lo4gj2Example.java*
> > >
> > > package testing;
> > >
> > > import java.awt.BorderLayout;
> > > import java.awt.Dimension;
> > > import java.io.IOException;
> > > import java.io.OutputStream;
> > >
> > > import javax.swing.JFrame;
> > > import javax.swing.JTable;
> > > import javax.swing.JTextArea;
> > > import javax.swing.border.TitledBorder;
> > > import javax.swing.table.AbstractTableModel;
> > >
> > > import org.apache.logging.log4j.LogManager;
> > > import org.apache.logging.log4j.Logger;
> > > import org.apache.logging.log4j.core.Filter;
> > > import org.apache.logging.log4j.core.Layout;
> > > import
> > org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> > > import org.apache.logging.log4j.core.appender.OutputStreamManager;
> > > import org.apache.logging.log4j.core.config.plugins.Plugin;
> > > import org.apache.logging.log4j.core.config.plugins.PluginElement;
> > > import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> > >
> > > 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 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) {
> > > logger.trace("Entering Log4j Example.");
> > > Hello hello = new Hello();
> > > if (!hello.callMe()) {
> > > logger.error("Ohh!Failed!");
> > > }
> > > logger.trace("Exiting Log4j Example.");
> > >  INSTANCE.run();
> > > }
> > > }
> > >
> > > *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>*
> > >
> >
> >
> >
> > --
> > E-Mail: garydgregory@gmail.com | ggregory@apache.org
> > Java Persistence with Hibernate, Second Edition
> > <http://www.manning.com/bauer3/>
> > JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
> > Spring Batch in Action <http://www.manning.com/templier/>
> > Blog: http://garygregory.wordpress.com
> > Home: http://garygregory.com/
> > Tweet! http://twitter.com/GaryGregory
> >
>



-- 
Matt Sicker <bo...@gmail.com>

Re: Issue of creating and configuring custom appenders

Posted by James Hutton <ja...@gmail.com>.
Yeah, ideally there's a limit to the buffer in both choices, however why
aren't you just logging to a file and using the jtextarea to display the
file contents? Then you don't have as much a worry about memory usage.
On Jun 4, 2014 8:27 AM, "Gary Gregory" <ga...@gmail.com> wrote:

> Note that you will shoot yourself in the foot with such an appender by
> causing memory to be exhausted unless the appender never lets the contents
> of the text area grow beyond some limit.
>
> Gary
>
>
> On Mon, Jun 2, 2014 at 3:05 AM, Alex Wu <al...@gmail.com> wrote:
>
> > Hi all, I have followed Ralph's suggestion in this issue and the source
> > code of ConsoleAppender from apache to tried to create a custom appender
> > for appending logs to a JTextArea.
> >
> > https://issues.apache.org/jira/browse/LOG4J2-303
> >
> > But I am having trouble to make it to work, could anyone please give me
> > some help for this?
> >
> > the problems I am facing are,
> >
> > - I cannot find a way to pass that JTextArea object to my
> TextAreaAppender
> > - I am also having problem creating the manager, in ConsoleAppender, they
> > use "new OutputStreamManager(data.os, data.type, data.layout)", and it's
> > actually a "protected" constructor, how is this possible? BTW, eclipse is
> > also showing error about this. *Actually, I got around with this by
> > creating a subclass of OutputStreamManager in my test and make the
> > constructor public, not sure if I have done it in a right way though.*
> >
> > Any help would be appreciated.
> >
> > Test classes are as follow,
> >
> > *TextAreaAppender.java*
> >
> > package testing;
> >
> > import java.io.IOException;
> > import java.io.OutputStream;
> > import java.io.Serializable;
> >
> > import javax.swing.JTextArea;
> >
> > import org.apache.logging.log4j.core.Filter;
> > import org.apache.logging.log4j.core.Layout;
> > import
> org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> > import org.apache.logging.log4j.core.appender.ManagerFactory;
> > import org.apache.logging.log4j.core.appender.OutputStreamManager;
> > 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.helpers.Booleans;
> > import org.apache.logging.log4j.core.layout.PatternLayout;
> >
> > import testing.ConsoleAppender.ConsoleManagerFactory;
> >
> >
> > 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 OutputStreamManager(data.os, data.type,
> > data.layout);// protected constructor???
> >         }
> >     }
> > }
> >
> > *Lo4gj2Example.java*
> >
> > package testing;
> >
> > import java.awt.BorderLayout;
> > import java.awt.Dimension;
> > import java.io.IOException;
> > import java.io.OutputStream;
> >
> > import javax.swing.JFrame;
> > import javax.swing.JTable;
> > import javax.swing.JTextArea;
> > import javax.swing.border.TitledBorder;
> > import javax.swing.table.AbstractTableModel;
> >
> > import org.apache.logging.log4j.LogManager;
> > import org.apache.logging.log4j.Logger;
> > import org.apache.logging.log4j.core.Filter;
> > import org.apache.logging.log4j.core.Layout;
> > import
> org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> > import org.apache.logging.log4j.core.appender.OutputStreamManager;
> > import org.apache.logging.log4j.core.config.plugins.Plugin;
> > import org.apache.logging.log4j.core.config.plugins.PluginElement;
> > import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> >
> > 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 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) {
> > logger.trace("Entering Log4j Example.");
> > Hello hello = new Hello();
> > if (!hello.callMe()) {
> > logger.error("Ohh!Failed!");
> > }
> > logger.trace("Exiting Log4j Example.");
> >  INSTANCE.run();
> > }
> > }
> >
> > *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>*
> >
>
>
>
> --
> E-Mail: garydgregory@gmail.com | ggregory@apache.org
> Java Persistence with Hibernate, Second Edition
> <http://www.manning.com/bauer3/>
> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
> Spring Batch in Action <http://www.manning.com/templier/>
> Blog: http://garygregory.wordpress.com
> Home: http://garygregory.com/
> Tweet! http://twitter.com/GaryGregory
>

Re: Issue of creating and configuring custom appenders

Posted by Gary Gregory <ga...@gmail.com>.
Note that you will shoot yourself in the foot with such an appender by
causing memory to be exhausted unless the appender never lets the contents
of the text area grow beyond some limit.

Gary


On Mon, Jun 2, 2014 at 3:05 AM, Alex Wu <al...@gmail.com> wrote:

> Hi all, I have followed Ralph's suggestion in this issue and the source
> code of ConsoleAppender from apache to tried to create a custom appender
> for appending logs to a JTextArea.
>
> https://issues.apache.org/jira/browse/LOG4J2-303
>
> But I am having trouble to make it to work, could anyone please give me
> some help for this?
>
> the problems I am facing are,
>
> - I cannot find a way to pass that JTextArea object to my TextAreaAppender
> - I am also having problem creating the manager, in ConsoleAppender, they
> use "new OutputStreamManager(data.os, data.type, data.layout)", and it's
> actually a "protected" constructor, how is this possible? BTW, eclipse is
> also showing error about this. *Actually, I got around with this by
> creating a subclass of OutputStreamManager in my test and make the
> constructor public, not sure if I have done it in a right way though.*
>
> Any help would be appreciated.
>
> Test classes are as follow,
>
> *TextAreaAppender.java*
>
> package testing;
>
> import java.io.IOException;
> import java.io.OutputStream;
> import java.io.Serializable;
>
> import javax.swing.JTextArea;
>
> import org.apache.logging.log4j.core.Filter;
> import org.apache.logging.log4j.core.Layout;
> import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> import org.apache.logging.log4j.core.appender.ManagerFactory;
> import org.apache.logging.log4j.core.appender.OutputStreamManager;
> 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.helpers.Booleans;
> import org.apache.logging.log4j.core.layout.PatternLayout;
>
> import testing.ConsoleAppender.ConsoleManagerFactory;
>
>
> 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 OutputStreamManager(data.os, data.type,
> data.layout);// protected constructor???
>         }
>     }
> }
>
> *Lo4gj2Example.java*
>
> package testing;
>
> import java.awt.BorderLayout;
> import java.awt.Dimension;
> import java.io.IOException;
> import java.io.OutputStream;
>
> import javax.swing.JFrame;
> import javax.swing.JTable;
> import javax.swing.JTextArea;
> import javax.swing.border.TitledBorder;
> import javax.swing.table.AbstractTableModel;
>
> import org.apache.logging.log4j.LogManager;
> import org.apache.logging.log4j.Logger;
> import org.apache.logging.log4j.core.Filter;
> import org.apache.logging.log4j.core.Layout;
> import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
> import org.apache.logging.log4j.core.appender.OutputStreamManager;
> import org.apache.logging.log4j.core.config.plugins.Plugin;
> import org.apache.logging.log4j.core.config.plugins.PluginElement;
> import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>
> 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 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) {
> logger.trace("Entering Log4j Example.");
> Hello hello = new Hello();
> if (!hello.callMe()) {
> logger.error("Ohh!Failed!");
> }
> logger.trace("Exiting Log4j Example.");
>  INSTANCE.run();
> }
> }
>
> *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>*
>



-- 
E-Mail: garydgregory@gmail.com | ggregory@apache.org
Java Persistence with Hibernate, Second Edition
<http://www.manning.com/bauer3/>
JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
Spring Batch in Action <http://www.manning.com/templier/>
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory