Hi

In one of my projects I have implemented a swing TextPane Appender. See below 
the two classes JTextPaneAppender and JLogoutputFrame.

The first one was copied (and enhanced) from a sample I found in the contribs 
package (but which did not work properly). The second one is a standalone 
window which shows the usage of the appender (which is created and configured 
by code). It is derived from Runnable in order to run in ist own thread.

I have no time to enhance the classes in order to have this appender full 
configurable by log4j config files. If you want, you can do anything with it as 
you like. There are a numer of TODO's within the code indicating which 
enhancements I would implement next.

Heri


package .....swingExtensions.log4j;

import java.awt.Color;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;

/**
 * Implements a log4j appender which writes to a swing JTextPane 
 *
 * This code was copied from 
 * 
"jakarta-log4j-1.2.15\apache-log4j-1.2.15\contribs\SvenReimers\gui\TextPaneAppender.java"
 * (which did not work properly, not even compile) and adapted for my needs.
 *
 * @author bender
 */
public class JTextPaneAppender extends AppenderSkeleton
{

    /**  */
    JTextPane         myTextPane;
    /**  */
    Hashtable<String,MutableAttributeSet>         myAttributeSet;

    /**
     * Constructor
     *
     * @param aLayout
     * @param aName
     * @param aFilterArray 
     * @param aTextPane
     */
    public JTextPaneAppender( Layout aLayout, String aName, Filter[] 
aFilterArray, JTextPane aTextPane )
    {
        this();
        this.layout = aLayout;
        this.name = aName;
        myTextPane = aTextPane;
        
        if ( aFilterArray != null )
        {
            for ( int i = 0; i < aFilterArray.length; i++ )
            {
                if ( aFilterArray[i] != null )
                {
                    addFilter( aFilterArray[i] );
                } // if aFilterArray[i] != null]
            } // for i
            
        } // if aFilterArray != null
        
        createAttributes();
    }

    /**
     * Constructor
     *
     */
    public JTextPaneAppender()
    {
        super();
        createAttributes();
    }

    /**
     * @see org.apache.log4j.AppenderSkeleton#close()
     */
    @Override
    public void close()
    {
        //
    }

    private void createAttributes()
    {
        String prio[] = new String[6];
        prio[0] = Level.FATAL.toString();
        prio[1] = Level.ERROR.toString();
        prio[2] = Level.WARN.toString();
        prio[3] = Level.INFO.toString();
        prio[4] = Level.DEBUG.toString();
        prio[5] = Level.TRACE.toString();
        
        myAttributeSet = new Hashtable<String,MutableAttributeSet>();
        
        for ( int i = 0; i < prio.length; i++ )
        {
            MutableAttributeSet att = new SimpleAttributeSet();
            myAttributeSet.put( prio[i], att );
            StyleConstants.setFontSize( att, 14 );
        }

        
StyleConstants.setForeground(myAttributeSet.get(Level.FATAL.toString()),Color.red);
        
StyleConstants.setForeground(myAttributeSet.get(Level.ERROR.toString()),Color.red);
        
StyleConstants.setForeground(myAttributeSet.get(Level.WARN.toString()),Color.orange);
        
StyleConstants.setForeground(myAttributeSet.get(Level.INFO.toString()),Color.black);
        
StyleConstants.setForeground(myAttributeSet.get(Level.DEBUG.toString()),Color.black);
        
StyleConstants.setForeground(myAttributeSet.get(Level.TRACE.toString()),Color.black);
    }

    /**
     * @see 
org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
     */
    @Override
    public void append( LoggingEvent event )
    {
        if ( myTextPane == null )
        {
            LogLog.warn( "TextPane is not initialized" );
            return;
        } // if myTextPane == null
        
        
        String text = this.layout.format( event );
        String[] stackTrace = event.getThrowableStrRep();
        if ( stackTrace != null )
        {
            StringBuffer sb = new StringBuffer( text );
            
            for ( int i = 0; i < stackTrace.length; i++ )
            {
                sb.append( "    " ).append( stackTrace[i] ).append( "\n" );
            } // for i
            
            text = sb.toString();
        }
        
        StyledDocument    myDoc = myTextPane.getStyledDocument();
        
        try
        {
            myDoc.insertString( myDoc.getLength(), text, myAttributeSet.get( 
event.getLevel().toString() ) );
        }
        catch ( BadLocationException badex )
        {
            System.err.println( badex );
        }
        
        myTextPane.setCaretPosition( myDoc.getLength() );
    }

    /**
     * getTextPane
     * <p>
     * @return
     */
    public JTextPane getTextPane()
    {
        return myTextPane;
    }

    /**
     * setTextPane
     * <p>
     * @param aTextpane
     */
    public void setTextPane( JTextPane aTextpane )
    {
        myTextPane = aTextpane;
    }

    private void setColor( Level p, Color v )
    {
        StyleConstants.setForeground( myAttributeSet.get( p ), v );
    }

    private Color getColor( Level p )
    {
        Color c = StyleConstants.getForeground( myAttributeSet.get( p ) );
        return c == null ? null : c;
    }

    // ///////////////////////////////////////////////////////////////////
    // option setters and getters

    /**
     * setColorEmerg
     * <p>
     * @param color
     */
    public void setColorEmerg( Color color )
    {
        setColor( Level.FATAL, color );
    }

    /**
     * getColorEmerg
     * <p>
     * @return
     */
    public Color getColorEmerg()
    {
        return getColor( Level.FATAL );
    }

    /**
     * setColorError
     * <p>
     * @param color
     */
    public void setColorError( Color color )
    {
        setColor( Level.ERROR, color );
    }

    /**
     * getColorError
     * <p>
     * @return
     */
    public Color getColorError()
    {
        return getColor( Level.ERROR );
    }

    /**
     * setColorWarn
     * <p>
     * @param color
     */
    public void setColorWarn( Color color )
    {
        setColor( Level.WARN, color );
    }

    /**
     * getColorWarn
     * <p>
     * @return
     */
    public Color getColorWarn()
    {
        return getColor( Level.WARN );
    }

    /**
     * setColorInfo
     * <p>
     * @param color
     */
    public void setColorInfo( Color color )
    {
        setColor( Level.INFO, color );
    }

    /**
     * getColorInfo
     * <p>
     * @return
     */
    public Color getColorInfo()
    {
        return getColor( Level.INFO );
    }

    /**
     * setColorDebug
     * <p>
     * @param color
     */
    public void setColorDebug( Color color )
    {
        setColor( Level.DEBUG, color );
    }

    /**
     * getColorDebug
     * <p>
     * @return
     */
    public Color getColorDebug()
    {
        return getColor( Level.DEBUG );
    }

    /**
     * Sets the font size of all Level's
     * <p>
     * @param aSize
     */
    public void setFontSize( int aSize )
    {
        Enumeration<MutableAttributeSet> e = myAttributeSet.elements();
        while ( e.hasMoreElements() )
        {
            StyleConstants.setFontSize( e.nextElement(), aSize );
        }
        return;
    }

    /**
     * Sets the font size of a particular Level
     * <p>
     * @param aSize
     * @param aLevel
     */
    public void setFontSize( int aSize, Level aLevel )
    {
        MutableAttributeSet set = myAttributeSet.get( aLevel );
        if ( set != null )
        {
            StyleConstants.setFontSize( set, aSize );
        } // if set != null
    }

    /**
     * getFontSize
     * <p>
     * @param aLevel
     * @return
     */
    public int getFontSize( Level aLevel )
    {
        AttributeSet attrSet = myAttributeSet.get( aLevel );
        if ( attrSet == null )
        {
            throw new IllegalArgumentException( "Unhandled Level: " + 
aLevel.toString() );
        } // if attrSet == null
        
        return StyleConstants.getFontSize( attrSet );
    }

    /**
     * Sets the font name of all known Level's
     * <p>
     * @param aName
     */
    public void setFontName( String aName )
    {
        Enumeration<MutableAttributeSet> e = myAttributeSet.elements();
        while ( e.hasMoreElements() )
        {
            StyleConstants.setFontFamily( e.nextElement(), aName );
        }
        return;
    }

    /**
     * setFontName
     * <p>
     * @param aName
     * @param aLevel
     */
    public void setFontName( String aName, Level aLevel )
    {
        MutableAttributeSet set = myAttributeSet.get( aLevel );
        if ( set != null )
        {
            StyleConstants.setFontFamily( set, aName );
        }
        return;
    }

    /**
     * Retrieves the font name of a particular Level
     * <p>
     * @param aLevel 
     * @return
     */
    public String getFontName( Level aLevel )
    {
        AttributeSet attrSet = myAttributeSet.get( aLevel );
        
        if ( attrSet == null )
        {
            throw new IllegalArgumentException( "Unhandled Level: " + 
aLevel.toString() );
        } // if attrSet == null
        
        return StyleConstants.getFontFamily( attrSet );
    }

    /**
     * @see org.apache.log4j.AppenderSkeleton#requiresLayout()
     */
    @Override
    public boolean requiresLayout()
    {
        return true;
    }
}

package ....swingExtensions.comp;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;

import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;

import ....swingExtensions.log4j.JTextPaneAppender;

/**
 *  a standalone window for receiving and displaying log outputs
 *  <p>
 *  Singleton pattern
 *  <p>
 *  The Frame and the appender are not shown by initializing it but
 *  only made ready to receive all log output. It can later be set to
 *  visible if desired.
 *  TODO: implement also a enable() and disable() method in order to 
 *  have a minimal impact on performance if not used.
 *
 * @author bender
 */
public class JLogoutputFrame implements Runnable
{
    private static final Logger myLog = Logger.getLogger( JLogoutputFrame.class 
);
//    private static final Log myLog = LogFactory.getLog( JLogoutputFrame.class 
);
    
    private static Layout myLayout = new PatternLayout( "%d{HH:mm:ss.SSS} (%6r) 
%-5p [%-7t] %F:%L %x - %m%n" );
    private static Vector<Filter> myFilters = new Vector<Filter>();
    
    private Object myWaiterToSignal = null;
    private static JLogoutputFrame myInstance = null;
    private JFrame myMainFrame = null;
    private JTextPaneAppender myAppender = null;

    /**
     * Retrieves the singleton instance
     * <p>
     * @return
     */
    public static JLogoutputFrame getInstance()
    {
        if ( myInstance == null )
        {
            initInstance();
        } // if myInstance == null
        
        return myInstance;
        
    }

    /**
     * initInstance
     * <p>
     */
    private static void initInstance()
    {
        Object waiter = new Object();
        myInstance = new JLogoutputFrame( waiter );
        SwingUtilities.invokeLater( myInstance );

        synchronized ( waiter )
        {
            try
            {
                waiter.wait();
            }
            catch ( InterruptedException e )
            {
                myLog.warn( "Problems while initializing log output", e );
            }
        } // synchronized (waiter)
    }
    
    /**
     * Constructor
     *
     */
    private JLogoutputFrame( Object aWaiterToSignal )
    {
        super();

        myWaiterToSignal = aWaiterToSignal;
    }

    /**
     * @see java.lang.Runnable#run()
     */
    public void run()
    {
        String methodName = "LogoutputFrame.run()";

        myLog.debug( methodName + " entering"  );

        try
        {
            synchronized ( myWaiterToSignal )
            {
                try
                {
                    myMainFrame = createMainFrame();
                }
                finally
                {
                    myWaiterToSignal.notify();
                }
            } // synchronized (waiter)
        }
        catch ( Throwable t )
        {
            myLog.error( "Exception catched in " + methodName, t );
        }

        myLog.debug( methodName + " leaving" );

    }

    /**
     * createMainFrame
     * <p>
     * @return the initialized main frame 
     */
    private JFrame createMainFrame()
    {
//        JPanel messagePane = createMessagePane();

        JFrame result = new JFrame();
        result.setPreferredSize( new Dimension( 400, 300 ) );
        
        JTextPane textPane = new JTextPane();
        myAppender = createAppender( textPane );
        textPane.setEditable( false );

        JScrollPane scrollPane = new JScrollPane( textPane );
        scrollPane.setPreferredSize( new Dimension( 400, 300 ) );
        result.getContentPane().add( scrollPane, BorderLayout.CENTER );

        String fontFamily = "Courier New";
        Font font = new Font( fontFamily, Font.PLAIN, 1 );
//        Font[] fonts = 
GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
//        for ( int i = 0; i < fonts.length; i++ )
//        {
//            if ( fonts[i].getFamily().equals( fontFamily ) )
//            {
//                textPane.setFont( fonts[i] );
//                break;
//            } // if fonts[i].getFamily().equals( fontFamily )
//        } // for i
        textPane.setFont( font );
        
        result.pack();
        
        result.setDefaultCloseOperation( JFrame.HIDE_ON_CLOSE );
        
        return result;
    }

    /**
     * Outputs a message only to the appender which belongs to this frame
     * <p>
     * @param fqcn 
     * @param aLevel 
     * @param aMsg
     */
    public void log( Level aLevel, String aMsg )
    {
        if ( myAppender == null )
        {
            return;
        } // if myAppender == null
        
        
        LoggingEvent event = new LoggingEvent( this.getClass().getName(), 
myLog, aLevel, aMsg, null );
        
        myAppender.append( event );
    }
    
    /**
     * Creates the appender and adds it to all known Loggers whose additivity 
     * flag is false, incl. root logger
     * <p>
     * @param aTextPane 
     * @return
     */
    @SuppressWarnings("unchecked")
    public JTextPaneAppender createAppender( JTextPane aTextPane )
    {
        JTextPaneAppender result = new JTextPaneAppender( myLayout, "Debug", 
myFilters.toArray( new Filter[0] ), aTextPane );
        
        // TODO: This a simple approach to add the new appender to all yet 
known Loggers. 
        // If Loggers are created dynamically later on or the the additivity 
flag of
        // a logger changes, these Loggers probably wouldn't log to this 
appender. Solution is to
        // override the DefaultLoggerFactory and the Logger's setAdditivity().
        // Better solution is: Derivation of HierarchyEventListener (see mail 
on log4j user list "logging relative to webapp context path in tomcat" from Mi 
19.03.2008 12:04)
        Enumeration en = LogManager.getCurrentLoggers();
        
        while ( en.hasMoreElements() )
        {
            Object o = en.nextElement();
            
            if ( o instanceof Logger )
            {
                Logger logger = ( Logger ) o;
                if ( !logger.getAdditivity() )
                {
                    logger.addAppender( result );
                } // if !logger.getAdditivity()
            } // if o instanceof Logger
            
        } // while ( en )
        
        LogManager.getRootLogger().addAppender( result );
        
        return result;
    }

    /**
     * @return the mainFrame
     */
    public JFrame getMainFrame()
    {
        return myMainFrame;
    }

    /**
     * @return the myLayout
     */
    public static Layout getLayout()
    {
        return myLayout;
    }

    /**
     * @param aLayout the Layout to set
     */
    public static void setMyPatternLayout( Layout aLayout )
    {
        if ( myInstance != null )
        {
            // TODO: enable swiching layout
            throw new IllegalStateException( "Cannot switch Layout after having 
initialized the frame" );
        } // if myInstance != null
        
        myLayout = aLayout;
    }

    /**
     * @return the myFilters
     */
    public static Vector<Filter> getFilters()
    {
        return myFilters;
    }

    /**
     * @param aFilters the Filters to set
     */
    public static void setFilters( Vector<Filter> aFilters )
    {
        if ( myInstance != null )
        {
            // TODO: enable swiching filters
            throw new IllegalStateException( "Cannot change filters after 
having initialized the frame" );
        } // if myInstance != null
        
        myFilters = aFilters;
    }

    /**
     * @param aFilter the Filter to be added
     */
    public static void addFilter( Filter aFilter )
    {
        if ( myInstance != null )
        {
            // TODO: enable adding filters
            throw new IllegalStateException( "Cannot add new filter after 
having initialized the frame" );
        } // if myInstance != null
        
        myFilters.add( aFilter );
    }

}


-----Ursprüngliche Nachricht-----
Von: Andy Rozman [mailto:a...@triera.net] 
Gesendet: Dienstag, 14. April 2009 23:01
An: log4j-user@logging.apache.org
Betreff: logging from another class

Hi !

I already asked this question once, but there were no answers then, I hope 
there will be one now... I have several classes which need to use logger. 
Theretically I could instantiate it in each class, but problem is that this 
message must also be used in some other module (log must be displayed in my 
swing applciation). So I wanted to create Util class which will a) write into 
log b) send info to swing application. Problem is that when I do that, I get 
that log message was created in this Util class. I need to know name and line 
of class that called this Util class, how could this be done? Is there 
possibility to do that?

Take care,
Andy

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-user-h...@logging.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-user-h...@logging.apache.org

Reply via email to