You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by ps...@apache.org on 2003/04/28 08:58:32 UTC
cvs commit: jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw ChainsawAppender.java ChainsawViewer.java EventDetails.java EventDetailSink.java MyTableModel.java
psmith 2003/04/27 23:58:32
Added: src/java/org/apache/log4j/chainsaw ChainsawAppender.java
ChainsawViewer.java EventDetails.java
EventDetailSink.java MyTableModel.java
Log:
These 'original' Chainsaw files are also needed to compile correctly.
Revision Changes Path
1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw/ChainsawAppender.java
Index: ChainsawAppender.java
===================================================================
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package org.apache.log4j.chainsaw;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.OptionConverter;
/**
* ChainsawAppender receives LoggingEvents from the local
* Log4J environment, and appends them into a model that
* can be used inside a Swing GUI
* @author Paul Smith
* @version 1.0
*/
public class ChainsawAppender
extends AppenderSkeleton
implements EventDetailSink, TableModel {
private final ArrayList appenders=new ArrayList();
/**
* Shared model used by the shared Appender
*/
private static MyTableModel sSharedModel;
/**
* The model that is used by this Appender, we ensure
* here that we only use a single Model as the current
* release is effetively an in-JVM singleton
*/
private final MyTableModel wrappedTableModel = getDefaultModel();
/**
* The in-JVM singleton instance of the ChainsawAppender.
*
* If somehow Log4j initialises more than one, then the first one to
* initialise wins!
*/
private static ChainsawAppender sSharedAppender = null;
/**
* The classname of the viewer to create to view the events.
*/
private String viewerClassname;
/**
* Constructor, initialises the singleton instance of the appender
*/
public ChainsawAppender() {
synchronized (ChainsawAppender.class) {
if (sSharedAppender == null) {
sSharedAppender = this;
}
}
}
/**
* Returns the singleton MyTableModel instance that has been configured.
*
* This will be eventually replaced to allow each ChainsawAppender
* to have it's own model, but for now it's important that all log events
* received inside Chainsaw go to a single model.
* @return MyTableModel
*/
private static synchronized MyTableModel getDefaultModel() {
if (sSharedModel == null) {
sSharedModel = new MyTableModel();
}
return sSharedModel;
}
/**
* Return the singleton instance of the ChainsawAppender, it should only
* be initialised once.
* @return the One and only instance of the ChainsawAppender that is
* allowed to be referenced by the GUI
*/
static ChainsawAppender getInstance() {
return sSharedAppender;
}
/**
* Returns the internally wrapped Model
*
* NOTE: it is strongly recommended at this time not to rely on this method
* until further refactoring is completed.
* @return MyTableModel the MyTableModel that can be used by external
* components
*/
MyTableModel getWrappedModel() {
return wrappedTableModel;
}
/**
* This appender does not require layout and so return false
* @return false and only false
*/
public boolean requiresLayout() {
return false;
}
public void addAppender(Appender appender) {
appenders.add(appender);
}
/**
* Implements the EventDetailSink interface by forwarding the EventDetails
* object onto an internal Model
* @param aDetails the EventDetails to add to the model
*/
public void addEvent(EventDetails aDetails) {
synchronized (wrappedTableModel) {
wrappedTableModel.addEvent(aDetails);
}
}
/**
* Appends the event into the internal wrapped TableModel
* @param aEvent the LoggingEvent to append
*/
protected void append(LoggingEvent aEvent) {
synchronized (wrappedTableModel) {
wrappedTableModel.addEvent(new EventDetails(aEvent));
}
for (int i=0;i<appenders.size();i++) {
Appender appender=(Appender)appenders.get(i);
appender.doAppend(aEvent);
}
}
/**
* Instantiates and activates an instance of a ChainsawViewer
* to view the contents of this appender.
*/
public void activateOptions() {
if (viewerClassname == null) {
viewerClassname = "org.apache.log4j.chainsaw.DefaultViewer";
}
ChainsawViewer viewer =
(ChainsawViewer) OptionConverter.instantiateByClassName(viewerClassname,
ChainsawViewer.class, null);
if (viewer != null) {
viewer.activateViewer(this);
}
}
/**
* Close does nothing
*/
public void close() {
/** @todo perhaps it should clear the internal TableModel */
}
/**
* Sets the viewer class to use to view the events. The class must
* implement the ChainsawViewer interface.
*
* @param classname The class name of the viewer class.
*/
public void setViewerClass(String classname) {
viewerClassname = classname;
}
/**
* Gets the viewer class to use to view the events.
*
* @return The class name of the viewer class.
*/
public String getViewerClass() {
return viewerClassname;
}
// ==========================================================================
// All methods here are from TableModel, and simply forward on to the
// internal wrappedTableModel instance
// ==========================================================================
/**
* Implementation of TableModel interface
* @return int rowCount
*/
public int getRowCount() {
return wrappedTableModel.getRowCount();
}
/**
* Implementation of TableModel interface
* @return int column Count
*/
public int getColumnCount() {
return wrappedTableModel.getColumnCount();
}
/**
* Implementation of TableModel interface
* @param aColumnIndex the Column index to query the name for
* @return String column name
*/
public String getColumnName(int aColumnIndex) {
return wrappedTableModel.getColumnName(aColumnIndex);
}
/**
* Implementation of TableModel interface
* @param columnIndex column Index to query the Class of
* @return Class class of Column
*/
public Class getColumnClass(int columnIndex) {
return wrappedTableModel.getColumnClass(columnIndex);
}
/**
* Implementation of TableModel interface
* @param rowIndex row Index to query
* @param columnIndex column Index to query
* @return boolean is Cell Editable?
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
return wrappedTableModel.isCellEditable(rowIndex, columnIndex);
}
/**
* Implementation of TableModel interface
* @param rowIndex the row index to retrieve value from
* @param columnIndex to the column index to retrieve value from
* @return Object value at a particular row/column point
*/
public Object getValueAt(int rowIndex, int columnIndex) {
return wrappedTableModel.getValueAt(rowIndex, columnIndex);
}
/**
* Implementation of TableModel interface
* @param aValue the value to set
* @param rowIndex the row
* @param columnIndex the column
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
wrappedTableModel.setValueAt(aValue, rowIndex, columnIndex);
}
/**
* Implementation of TableModel interface
* @param l a TableModelListener to add
*/
public void addTableModelListener(TableModelListener l) {
wrappedTableModel.addTableModelListener(l);
}
/**
* Implementation of TableModel interface
* @param l listener to remove from the currently registered listeners
*/
public void removeTableModelListener(TableModelListener l) {
wrappedTableModel.removeTableModelListener(l);
}
}
1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw/ChainsawViewer.java
Index: ChainsawViewer.java
===================================================================
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package org.apache.log4j.chainsaw;
/**
Chainsaw compatible gui viewers must implement this interface
in order to be opened and configured by the ChainsawAppender class.
@author Mark Womack
*/
public interface ChainsawViewer {
/**
Called when the viewer should activate.
@param model The ChainsawAppender model instance the viewer should use. */
void activateViewer(ChainsawAppender model);
}
1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw/EventDetails.java
Index: EventDetails.java
===================================================================
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package org.apache.log4j.chainsaw;
import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Priority;
import org.apache.log4j.spi.LoggingEvent;
/**
* Represents the details of a logging event. It is intended to overcome the
* problem that a LoggingEvent cannot be constructed with purely fake data.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
* @version 1.0
*/
class EventDetails {
/** the time of the event **/
private final long mTimeStamp;
/** the priority of the event **/
private final Priority mPriority;
/** the category of the event **/
private final String mCategoryName;
/** the NDC for the event **/
private final String mNDC;
/** the MDC for the event **/
private final String mMDC;
/** the Properties for the event **/
private final String mProperties;
/** the thread for the event **/
private final String mThreadName;
/** the msg for the event **/
private final String mMessage;
/** the throwable details the event **/
private final String[] mThrowableStrRep;
/** the location details for the event **/
private final String mLocationDetails;
/**
* Creates a new <code>EventDetails</code> instance.
* @param aTimeStamp a <code>long</code> value
* @param aPriority a <code>Priority</code> value
* @param aCategoryName a <code>String</code> value
* @param aNDC a <code>String</code> value
* @param aThreadName a <code>String</code> value
* @param aMessage a <code>String</code> value
* @param aThrowableStrRep a <code>String[]</code> value
* @param aLocationDetails a <code>String</code> value
*/
EventDetails(
long aTimeStamp, Priority aPriority, String aCategoryName, String aNDC,
String aMDC, String aProperties, String aThreadName, String aMessage,
String[] aThrowableStrRep, String aLocationDetails) {
mTimeStamp = aTimeStamp;
mPriority = aPriority;
mCategoryName = aCategoryName;
mNDC = aNDC;
mMDC = aMDC;
mProperties = aProperties;
mThreadName = aThreadName;
mMessage = aMessage;
mThrowableStrRep = aThrowableStrRep;
mLocationDetails = aLocationDetails;
}
/**
* Creates a new <code>EventDetails</code> instance.
*
* @param aEvent a <code>LoggingEvent</code> value
*/
EventDetails(LoggingEvent aEvent) {
this(
aEvent.timeStamp, aEvent.getLevel(), aEvent.getLoggerName(),
aEvent.getNDC(), getEventMDC(aEvent), getEventProperties(aEvent),
aEvent.getThreadName(), aEvent.getRenderedMessage(),
aEvent.getThrowableStrRep(),
(aEvent.getLocationInformation() == null) ? null
: aEvent
.getLocationInformation().fullInfo);
}
/** @see #mTimeStamp **/
long getTimeStamp() {
return mTimeStamp;
}
/** @see #mPriority **/
Priority getPriority() {
return mPriority;
}
/** @see #mCategoryName **/
String getCategoryName() {
return mCategoryName;
}
/** @see #mNDC **/
String getNDC() {
return mNDC;
}
/** @see #mMDC **/
String getMDC() {
return mMDC;
}
/** @see #mProperties **/
String getProperties() {
return mProperties;
}
/** @see #mThreadName **/
String getThreadName() {
return mThreadName;
}
/** @see #mMessage **/
String getMessage() {
return mMessage;
}
/** @see #mLocationDetails **/
String getLocationDetails() {
return mLocationDetails;
}
/** @see #mThrowableStrRep **/
String[] getThrowableStrRep() {
return mThrowableStrRep;
}
/**
Used internally to convert the MDC contents to a string.
@param event The LoggingEvent to use for the MDC contents.
@return String The MDC contents in string form. */
private static String getEventMDC(LoggingEvent event) {
Set keySet = event.getMDCKeySet();
if (!keySet.isEmpty()) {
String mdcString = "";
Iterator keyIter = keySet.iterator();
while (keyIter.hasNext()) {
if (mdcString.length() != 0) {
mdcString += ',';
}
String key = (String)keyIter.next();
String value = (String)event.getMDC(key);
mdcString += key + "=" + value;
}
return mdcString;
}
return null;
}
/**
Used internally to convert the properties contents to a string.
@param event The LoggingEvent to use for the properties contents.
@return String The properties contents in string form. */
private static String getEventProperties(LoggingEvent event) {
Set keySet = event.getPropertyKeySet();
if (!keySet.isEmpty()) {
String propertyString = "";
Iterator keyIter = keySet.iterator();
while (keyIter.hasNext()) {
if (propertyString.length() != 0) {
propertyString += ',';
}
String key = (String)keyIter.next();
String value = (String)event.getProperty(key);
propertyString += key + "=" + value;
}
return propertyString;
}
return null;
}
}
1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw/EventDetailSink.java
Index: EventDetailSink.java
===================================================================
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package org.apache.log4j.chainsaw;
/**
* Simple interface for objects that can receive/work with EventDetails
* instances
* @author Paul Smith
* @version 1.0
*/
public interface EventDetailSink {
void addEvent(EventDetails aDetail);
}
1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/chainsaw/MyTableModel.java
Index: MyTableModel.java
===================================================================
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package org.apache.log4j.chainsaw;
import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.table.AbstractTableModel;
/**
* Represents a list of <code>EventDetails</code> objects that are sorted on
* logging time. Methods are provided to filter the events that are visible.
*
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
class MyTableModel extends AbstractTableModel implements EventDetailSink {
/** used to log messages **/
private static final Category LOG = Category.getInstance(MyTableModel.class);
/** use the compare logging events **/
private static final Comparator MY_COMP =
new Comparator() {
/** @see Comparator **/
public int compare(Object aObj1, Object aObj2) {
if ((aObj1 == null) && (aObj2 == null)) {
return 0; // treat as equal
} else if (aObj1 == null) {
return -1; // null less than everything
} else if (aObj2 == null) {
return 1; // think about it. :->
}
// will assume only have LoggingEvent
final EventDetails le1 = (EventDetails) aObj1;
final EventDetails le2 = (EventDetails) aObj2;
if (le1.getTimeStamp() < le2.getTimeStamp()) {
return 1;
}
// assume not two events are logged at exactly the same time
return -1;
}
};
/** names of the columns in the table **/
private static final String[] COL_NAMES =
{ "Time", "Priority", "Trace", "Category", "NDC", "MDC", "Properties", "Message" };
/** definition of an empty list **/
private static final EventDetails[] EMPTY_LIST = new EventDetails[] { };
/** used to format dates **/
private static final DateFormat DATE_FORMATTER =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
/** the lock to control access **/
private final Object mLock = new Object();
/** set of all logged events - not filtered **/
private final SortedSet mAllEvents = new TreeSet(MY_COMP);
/** events that are visible after filtering **/
private EventDetails[] mFilteredEvents = EMPTY_LIST;
/** list of events that are buffered for processing **/
private final List mPendingEvents = new ArrayList();
/** indicates whether event collection is paused to the UI **/
private boolean mPaused = false;
/** filter for the thread **/
private String mThreadFilter = "";
/** filter for the message **/
private String mMessageFilter = "";
/** filter for the NDC **/
private String mNDCFilter = "";
/** filter for the MDC **/
private String mMDCFilter = "";
/** filter for the Properties **/
private String mPropertiesFilter = "";
/** filter for the category **/
private String mCategoryFilter = "";
/** filter for the priority **/
private Priority mPriorityFilter = Priority.DEBUG;
/**
* Creates a new <code>MyTableModel</code> instance.
*
*/
MyTableModel() {
final Thread t = new Thread(new Processor());
t.setDaemon(true);
t.start();
}
////////////////////////////////////////////////////////////////////////////
// Table Methods
////////////////////////////////////////////////////////////////////////////
/** @see javax.swing.table.TableModel **/
public int getRowCount() {
synchronized (mLock) {
return mFilteredEvents.length;
}
}
/** @see javax.swing.table.TableModel **/
public int getColumnCount() {
// does not need to be synchronized
return COL_NAMES.length;
}
/** @see javax.swing.table.TableModel **/
public String getColumnName(int aCol) {
// does not need to be synchronized
return COL_NAMES[aCol];
}
/** @see javax.swing.table.TableModel **/
public Class getColumnClass(int aCol) {
// does not need to be synchronized
return (aCol == 2) ? Boolean.class : Object.class;
}
/** @see javax.swing.table.TableModel **/
public Object getValueAt(int aRow, int aCol) {
synchronized (mLock) {
final EventDetails event = mFilteredEvents[aRow];
if (aCol == 0) {
return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
} else if (aCol == 1) {
return event.getPriority();
} else if (aCol == 2) {
return (event.getThrowableStrRep() == null) ? Boolean.FALSE
: Boolean.TRUE;
} else if (aCol == 3) {
return event.getCategoryName();
} else if (aCol == 4) {
return event.getNDC();
} else if (aCol == 5) {
return event.getMDC();
} else if (aCol == 6) {
return event.getProperties();
}
return event.getMessage();
}
}
////////////////////////////////////////////////////////////////////////////
// Public Methods
////////////////////////////////////////////////////////////////////////////
/**
* Sets the priority to filter events on. Only events of equal or higher
* property are now displayed.
*
* @param aPriority the priority to filter on
*/
public void setPriorityFilter(Priority aPriority) {
synchronized (mLock) {
mPriorityFilter = aPriority;
updateFilteredEvents(false);
}
}
/**
* Set the filter for the thread field.
*
* @param aStr the string to match
*/
public void setThreadFilter(String aStr) {
synchronized (mLock) {
mThreadFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the message field.
*
* @param aStr the string to match
*/
public void setMessageFilter(String aStr) {
synchronized (mLock) {
mMessageFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the NDC field.
*
* @param aStr the string to match
*/
public void setNDCFilter(String aStr) {
synchronized (mLock) {
mNDCFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the MDC field.
*
* @param aStr the string to match
*/
public void setMDCFilter(String aStr) {
synchronized (mLock) {
mMDCFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the Properties field.
*
* @param aStr the string to match
*/
public void setPropertiesFilter(String aStr) {
synchronized (mLock) {
mPropertiesFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Set the filter for the category field.
*
* @param aStr the string to match
*/
public void setCategoryFilter(String aStr) {
synchronized (mLock) {
mCategoryFilter = aStr.trim();
updateFilteredEvents(false);
}
}
/**
* Add an event to the list.
*
* @param aEvent a <code>EventDetails</code> value
*/
public void addEvent(EventDetails aEvent) {
synchronized (mLock) {
mPendingEvents.add(aEvent);
}
}
/**
* Clear the list of all events.
*/
public void clear() {
synchronized (mLock) {
mAllEvents.clear();
mFilteredEvents = new EventDetails[0];
mPendingEvents.clear();
fireTableDataChanged();
}
}
/** Toggle whether collecting events **/
public void toggle() {
synchronized (mLock) {
mPaused = !mPaused;
}
}
/** @return whether currently paused collecting events **/
public boolean isPaused() {
synchronized (mLock) {
return mPaused;
}
}
/**
* Get the throwable information at a specified row in the filtered events.
*
* @param aRow the row index of the event
* @return the throwable information
*/
public EventDetails getEventDetails(int aRow) {
synchronized (mLock) {
return mFilteredEvents[aRow];
}
}
////////////////////////////////////////////////////////////////////////////
// Private methods
////////////////////////////////////////////////////////////////////////////
/**
* Update the filtered events data structure.
* @param aInsertedToFront indicates whether events were added to front of
* the events. If true, then the current first event must still exist
* in the list after the filter is applied.
*/
private void updateFilteredEvents(boolean aInsertedToFront) {
final long start = System.currentTimeMillis();
final List filtered = new ArrayList();
final int size = mAllEvents.size();
final Iterator it = mAllEvents.iterator();
while (it.hasNext()) {
final EventDetails event = (EventDetails) it.next();
if (matchFilter(event)) {
filtered.add(event);
}
}
final EventDetails lastFirst =
(mFilteredEvents.length == 0) ? null : mFilteredEvents[0];
mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
if (aInsertedToFront && (lastFirst != null)) {
final int index = filtered.indexOf(lastFirst);
if (index < 1) {
LOG.warn("In strange state");
fireTableDataChanged();
} else {
fireTableRowsInserted(0, index - 1);
}
} else {
fireTableDataChanged();
}
final long end = System.currentTimeMillis();
LOG.debug(
"Total time [ms]: " + (end - start) + " in update, size: " + size);
}
/**
* Returns whether an event matches the filters.
*
* @param aEvent the event to check for a match
* @return whether the event matches
*/
private boolean matchFilter(EventDetails aEvent) {
if (
aEvent.getPriority().isGreaterOrEqual(mPriorityFilter)
&& (aEvent.getThreadName().indexOf(mThreadFilter) >= 0)
&& (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0)
&& ((mNDCFilter.length() == 0)
|| ((aEvent.getNDC() != null)
&& (aEvent.getNDC().indexOf(mNDCFilter) >= 0)))
&& ((mMDCFilter.length() == 0)
|| ((aEvent.getMDC() != null)
&& (aEvent.getMDC().indexOf(mMDCFilter) >= 0)))
&& ((mPropertiesFilter.length() == 0)
|| ((aEvent.getProperties() != null)
&& (aEvent.getProperties().indexOf(mPropertiesFilter) >= 0)))) {
final String rm = aEvent.getMessage();
if (rm == null) {
// only match if we have not filtering in place
return (mMessageFilter.length() == 0);
} else {
return (rm.indexOf(mMessageFilter) >= 0);
}
}
return false; // by default not match
}
/**
* Helper that actually processes incoming events.
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
private class Processor implements Runnable {
/** loops getting the events **/
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore
}
synchronized (mLock) {
if (mPaused) {
continue;
}
boolean toHead = true; // were events added to head
boolean needUpdate = false;
final Iterator it = mPendingEvents.iterator();
while (it.hasNext()) {
final EventDetails event = (EventDetails) it.next();
mAllEvents.add(event);
toHead = toHead && (event == mAllEvents.first());
needUpdate = needUpdate || matchFilter(event);
}
mPendingEvents.clear();
if (needUpdate) {
updateFilteredEvents(toHead);
}
}
}
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org