You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gr...@apache.org on 2012/06/02 13:41:11 UTC
svn commit: r1345492 [9/18] - in /logging/log4j/branches/log4j12modules: ./
contribs/ contribs/CekiGulcu/ contribs/EirikLygre/ contribs/JamesHouse/
contribs/Jamie Tsao/ contribs/JimMoore/ contribs/KevinSteppe/
contribs/KitchingSimon/ contribs/LeosLiter...
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig Sat Jun 2 11:40:31 2012
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * A daemon thread the processes connections from a
+ * <code>org.apache.log4j.net.SocketAppender.html</code>.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+class LoggingReceiver extends Thread {
+ /** used to log messages **/
+ private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
+
+ /**
+ * Helper that actually processes a client connection. It receives events
+ * and adds them to the supplied model.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+ private class Slurper implements Runnable {
+ /** socket connection to read events from **/
+ private final Socket mClient;
+
+ /**
+ * Creates a new <code>Slurper</code> instance.
+ *
+ * @param aClient socket to receive events from
+ */
+ Slurper(Socket aClient) {
+ mClient = aClient;
+ }
+
+ /** loops getting the events **/
+ public void run() {
+ LOG.debug("Starting to get data");
+ try {
+ final ObjectInputStream ois =
+ new ObjectInputStream(mClient.getInputStream());
+ while (true) {
+ final LoggingEvent event = (LoggingEvent) ois.readObject();
+ mModel.addEvent(new EventDetails(event));
+ }
+ } catch (EOFException e) {
+ LOG.info("Reached EOF, closing connection");
+ } catch (SocketException e) {
+ LOG.info("Caught SocketException, closing connection");
+ } catch (IOException e) {
+ LOG.warn("Got IOException, closing connection", e);
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Got ClassNotFoundException, closing connection", e);
+ }
+
+ try {
+ mClient.close();
+ } catch (IOException e) {
+ LOG.warn("Error closing connection", e);
+ }
+ }
+ }
+
+ /** where to put the events **/
+ private MyTableModel mModel;
+
+ /** server for listening for connections **/
+ private ServerSocket mSvrSock;
+
+ /**
+ * Creates a new <code>LoggingReceiver</code> instance.
+ *
+ * @param aModel model to place put received into
+ * @param aPort port to listen on
+ * @throws IOException if an error occurs
+ */
+ LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
+ setDaemon(true);
+ mModel = aModel;
+ mSvrSock = new ServerSocket(aPort);
+ }
+
+ /** Listens for client connections **/
+ public void run() {
+ LOG.info("Thread started");
+ try {
+ while (true) {
+ LOG.debug("Waiting for a connection");
+ final Socket client = mSvrSock.accept();
+ LOG.debug("Got a connection from " +
+ client.getInetAddress().getHostName());
+ final Thread t = new Thread(new Slurper(client));
+ t.setDaemon(true);
+ t.start();
+ }
+ } catch (IOException e) {
+ LOG.error("Error in accepting connections, stopping.", e);
+ }
+ }
+}
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java Sat Jun 2 11:40:31 2012
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.Properties;
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+/**
+ * The main application.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+public class Main
+ extends JFrame
+{
+ /** the default port number to listen on **/
+ private static final int DEFAULT_PORT = 4445;
+
+ /** name of property for port name **/
+ public static final String PORT_PROP_NAME = "chainsaw.port";
+
+ /** use to log messages **/
+ private static final Logger LOG = Logger.getLogger(Main.class);
+
+
+ /**
+ * Creates a new <code>Main</code> instance.
+ */
+ private Main() {
+ super("CHAINSAW - Log4J Log Viewer");
+ // create the all important model
+ final MyTableModel model = new MyTableModel();
+
+ //Create the menu bar.
+ final JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ final JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ try {
+ final LoadXMLAction lxa = new LoadXMLAction(this, model);
+ final JMenuItem loadMenuItem = new JMenuItem("Load file...");
+ menu.add(loadMenuItem);
+ loadMenuItem.addActionListener(lxa);
+ } catch (NoClassDefFoundError e) {
+ LOG.info("Missing classes for XML parser", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "XML parser not in classpath - unable to load XML events.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (Exception e) {
+ LOG.info("Unable to create the action to load XML files", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to create a XML parser - unable to load XML events.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ final JMenuItem exitMenuItem = new JMenuItem("Exit");
+ menu.add(exitMenuItem);
+ exitMenuItem.addActionListener(ExitAction.INSTANCE);
+
+ // Add control panel
+ final ControlPanel cp = new ControlPanel(model);
+ getContentPane().add(cp, BorderLayout.NORTH);
+
+ // Create the table
+ final JTable table = new JTable(model);
+ table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ final JScrollPane scrollPane = new JScrollPane(table);
+ scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
+ scrollPane.setPreferredSize(new Dimension(900, 300));
+
+ // Create the details
+ final JPanel details = new DetailPanel(table, model);
+ details.setPreferredSize(new Dimension(900, 300));
+
+ // Add the table and stack trace into a splitter
+ final JSplitPane jsp =
+ new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
+ getContentPane().add(jsp, BorderLayout.CENTER);
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent aEvent) {
+ ExitAction.INSTANCE.actionPerformed(null);
+ }
+ });
+
+ pack();
+ setVisible(true);
+
+ setupReceiver(model);
+ }
+
+ /**
+ * Setup recieving messages.
+ *
+ * @param aModel a <code>MyTableModel</code> value
+ */
+ private void setupReceiver(MyTableModel aModel) {
+ int port = DEFAULT_PORT;
+ final String strRep = System.getProperty(PORT_PROP_NAME);
+ if (strRep != null) {
+ try {
+ port = Integer.parseInt(strRep);
+ } catch (NumberFormatException nfe) {
+ LOG.fatal("Unable to parse " + PORT_PROP_NAME +
+ " property with value " + strRep + ".");
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to parse port number from '" + strRep +
+ "', quitting.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ System.exit(1);
+ }
+ }
+
+ try {
+ final LoggingReceiver lr = new LoggingReceiver(aModel, port);
+ lr.start();
+ } catch (IOException e) {
+ LOG.fatal("Unable to connect to socket server, quiting", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to create socket on port " + port + ", quitting.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ System.exit(1);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // static methods
+ ////////////////////////////////////////////////////////////////////////////
+
+
+ /** initialise log4j **/
+ private static void initLog4J() {
+ final Properties props = new Properties();
+ props.setProperty("log4j.rootLogger", "DEBUG, A1");
+ props.setProperty("log4j.appender.A1",
+ "org.apache.log4j.ConsoleAppender");
+ props.setProperty("log4j.appender.A1.layout",
+ "org.apache.log4j.TTCCLayout");
+ PropertyConfigurator.configure(props);
+ }
+
+ /**
+ * The main method.
+ *
+ * @param aArgs ignored
+ */
+ public static void main(String[] aArgs) {
+ initLog4J();
+ new Main();
+ }
+}
Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig Sat Jun 2 11:40:31 2012
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.Properties;
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+/**
+ * The main application.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+public class Main
+ extends JFrame
+{
+ /** the default port number to listen on **/
+ private static final int DEFAULT_PORT = 4445;
+
+ /** name of property for port name **/
+ public static final String PORT_PROP_NAME = "chainsaw.port";
+
+ /** use to log messages **/
+ private static final Logger LOG = Logger.getLogger(Main.class);
+
+
+ /**
+ * Creates a new <code>Main</code> instance.
+ */
+ private Main() {
+ super("CHAINSAW - Log4J Log Viewer");
+ // create the all important model
+ final MyTableModel model = new MyTableModel();
+
+ //Create the menu bar.
+ final JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ final JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ try {
+ final LoadXMLAction lxa = new LoadXMLAction(this, model);
+ final JMenuItem loadMenuItem = new JMenuItem("Load file...");
+ menu.add(loadMenuItem);
+ loadMenuItem.addActionListener(lxa);
+ } catch (NoClassDefFoundError e) {
+ LOG.info("Missing classes for XML parser", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "XML parser not in classpath - unable to load XML events.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (Exception e) {
+ LOG.info("Unable to create the action to load XML files", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to create a XML parser - unable to load XML events.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ final JMenuItem exitMenuItem = new JMenuItem("Exit");
+ menu.add(exitMenuItem);
+ exitMenuItem.addActionListener(ExitAction.INSTANCE);
+
+ // Add control panel
+ final ControlPanel cp = new ControlPanel(model);
+ getContentPane().add(cp, BorderLayout.NORTH);
+
+ // Create the table
+ final JTable table = new JTable(model);
+ table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ final JScrollPane scrollPane = new JScrollPane(table);
+ scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
+ scrollPane.setPreferredSize(new Dimension(900, 300));
+
+ // Create the details
+ final JPanel details = new DetailPanel(table, model);
+ details.setPreferredSize(new Dimension(900, 300));
+
+ // Add the table and stack trace into a splitter
+ final JSplitPane jsp =
+ new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
+ getContentPane().add(jsp, BorderLayout.CENTER);
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent aEvent) {
+ ExitAction.INSTANCE.actionPerformed(null);
+ }
+ });
+
+ pack();
+ setVisible(true);
+
+ setupReceiver(model);
+ }
+
+ /**
+ * Setup recieving messages.
+ *
+ * @param aModel a <code>MyTableModel</code> value
+ */
+ private void setupReceiver(MyTableModel aModel) {
+ int port = DEFAULT_PORT;
+ final String strRep = System.getProperty(PORT_PROP_NAME);
+ if (strRep != null) {
+ try {
+ port = Integer.parseInt(strRep);
+ } catch (NumberFormatException nfe) {
+ LOG.fatal("Unable to parse " + PORT_PROP_NAME +
+ " property with value " + strRep + ".");
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to parse port number from '" + strRep +
+ "', quitting.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ System.exit(1);
+ }
+ }
+
+ try {
+ final LoggingReceiver lr = new LoggingReceiver(aModel, port);
+ lr.start();
+ } catch (IOException e) {
+ LOG.fatal("Unable to connect to socket server, quiting", e);
+ JOptionPane.showMessageDialog(
+ this,
+ "Unable to create socket on port " + port + ", quitting.",
+ "CHAINSAW",
+ JOptionPane.ERROR_MESSAGE);
+ System.exit(1);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // static methods
+ ////////////////////////////////////////////////////////////////////////////
+
+
+ /** initialise log4j **/
+ private static void initLog4J() {
+ final Properties props = new Properties();
+ props.setProperty("log4j.rootLogger", "DEBUG, A1");
+ props.setProperty("log4j.appender.A1",
+ "org.apache.log4j.ConsoleAppender");
+ props.setProperty("log4j.appender.A1.layout",
+ "org.apache.log4j.TTCCLayout");
+ PropertyConfigurator.configure(props);
+ }
+
+ /**
+ * The main method.
+ *
+ * @param aArgs ignored
+ */
+ public static void main(String[] aArgs) {
+ initLog4J();
+ new Main();
+ }
+}
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java Sat Jun 2 11:40:31 2012
@@ -0,0 +1,390 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+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;
+import org.apache.log4j.Priority;
+import org.apache.log4j.Logger;
+
+/**
+ * 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
+{
+
+ /** used to log messages **/
+ private static final Logger LOG = Logger.getLogger(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;
+ }
+ };
+
+ /**
+ * 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);
+ }
+ }
+ }
+
+ }
+ }
+
+
+ /** names of the columns in the table **/
+ private static final String[] COL_NAMES = {
+ "Time", "Priority", "Trace", "Category", "NDC", "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 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();
+ }
+ 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 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))))
+ {
+ 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
+ }
+}
Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig Sat Jun 2 11:40:31 2012
@@ -0,0 +1,390 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+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;
+import org.apache.log4j.Priority;
+import org.apache.log4j.Logger;
+
+/**
+ * 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
+{
+
+ /** used to log messages **/
+ private static final Logger LOG = Logger.getLogger(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;
+ }
+ };
+
+ /**
+ * 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);
+ }
+ }
+ }
+
+ }
+ }
+
+
+ /** names of the columns in the table **/
+ private static final String[] COL_NAMES = {
+ "Time", "Priority", "Trace", "Category", "NDC", "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 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();
+ }
+ 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 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))))
+ {
+ 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
+ }
+}
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java Sat Jun 2 11:40:31 2012
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.util.StringTokenizer;
+import org.apache.log4j.Level;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A content handler for document containing Log4J events logged using the
+ * XMLLayout class. It will create events and add them to a supplied model.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ * @version 1.0
+ */
+class XMLFileHandler
+ extends DefaultHandler
+{
+ /** represents the event tag **/
+ private static final String TAG_EVENT = "log4j:event";
+ /** represents the message tag **/
+ private static final String TAG_MESSAGE = "log4j:message";
+ /** represents the ndc tag **/
+ private static final String TAG_NDC = "log4j:NDC";
+ /** represents the throwable tag **/
+ private static final String TAG_THROWABLE = "log4j:throwable";
+ /** represents the location info tag **/
+ private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
+
+ /** where to put the events **/
+ private final MyTableModel mModel;
+ /** the number of events in the document **/
+ private int mNumEvents;
+
+ /** the time of the event **/
+ private long mTimeStamp;
+ /** the priority (level) of the event **/
+ private Level mLevel;
+ /** the category of the event **/
+ private String mCategoryName;
+ /** the NDC for the event **/
+ private String mNDC;
+ /** the thread for the event **/
+ private String mThreadName;
+ /** the msg for the event **/
+ private String mMessage;
+ /** the throwable details the event **/
+ private String[] mThrowableStrRep;
+ /** the location details for the event **/
+ private String mLocationDetails;
+ /** buffer for collecting text **/
+ private final StringBuffer mBuf = new StringBuffer();
+
+ /**
+ * Creates a new <code>XMLFileHandler</code> instance.
+ *
+ * @param aModel where to add the events
+ */
+ XMLFileHandler(MyTableModel aModel) {
+ mModel = aModel;
+ }
+
+ /** @see DefaultHandler **/
+ public void startDocument()
+ throws SAXException
+ {
+ mNumEvents = 0;
+ }
+
+ /** @see DefaultHandler **/
+ public void characters(char[] aChars, int aStart, int aLength) {
+ mBuf.append(String.valueOf(aChars, aStart, aLength));
+ }
+
+ /** @see DefaultHandler **/
+ public void endElement(String aNamespaceURI,
+ String aLocalName,
+ String aQName)
+ {
+ if (TAG_EVENT.equals(aQName)) {
+ addEvent();
+ resetData();
+ } else if (TAG_NDC.equals(aQName)) {
+ mNDC = mBuf.toString();
+ } else if (TAG_MESSAGE.equals(aQName)) {
+ mMessage = mBuf.toString();
+ } else if (TAG_THROWABLE.equals(aQName)) {
+ final StringTokenizer st =
+ new StringTokenizer(mBuf.toString(), "\n\t");
+ mThrowableStrRep = new String[st.countTokens()];
+ if (mThrowableStrRep.length > 0) {
+ mThrowableStrRep[0] = st.nextToken();
+ for (int i = 1; i < mThrowableStrRep.length; i++) {
+ mThrowableStrRep[i] = "\t" + st.nextToken();
+ }
+ }
+ }
+ }
+
+ /** @see DefaultHandler **/
+ public void startElement(String aNamespaceURI,
+ String aLocalName,
+ String aQName,
+ Attributes aAtts)
+ {
+ mBuf.setLength(0);
+
+ if (TAG_EVENT.equals(aQName)) {
+ mThreadName = aAtts.getValue("thread");
+ mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
+ mCategoryName = aAtts.getValue("logger");
+ mLevel = Level.toLevel(aAtts.getValue("level"));
+ } else if (TAG_LOCATION_INFO.equals(aQName)) {
+ mLocationDetails = aAtts.getValue("class") + "."
+ + aAtts.getValue("method")
+ + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+ + ")";
+ }
+ }
+
+ /** @return the number of events in the document **/
+ int getNumEvents() {
+ return mNumEvents;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Private methods
+ ////////////////////////////////////////////////////////////////////////////
+
+ /** Add an event to the model **/
+ private void addEvent() {
+ mModel.addEvent(new EventDetails(mTimeStamp,
+ mLevel,
+ mCategoryName,
+ mNDC,
+ mThreadName,
+ mMessage,
+ mThrowableStrRep,
+ mLocationDetails));
+ mNumEvents++;
+ }
+
+ /** Reset the data for an event **/
+ private void resetData() {
+ mTimeStamp = 0;
+ mLevel = null;
+ mCategoryName = null;
+ mNDC = null;
+ mThreadName = null;
+ mMessage = null;
+ mThrowableStrRep = null;
+ mLocationDetails = null;
+ }
+}
Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig Sat Jun 2 11:40:31 2012
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.util.StringTokenizer;
+import org.apache.log4j.Level;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A content handler for document containing Log4J events logged using the
+ * XMLLayout class. It will create events and add them to a supplied model.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ * @version 1.0
+ */
+class XMLFileHandler
+ extends DefaultHandler
+{
+ /** represents the event tag **/
+ private static final String TAG_EVENT = "log4j:event";
+ /** represents the message tag **/
+ private static final String TAG_MESSAGE = "log4j:message";
+ /** represents the ndc tag **/
+ private static final String TAG_NDC = "log4j:NDC";
+ /** represents the throwable tag **/
+ private static final String TAG_THROWABLE = "log4j:throwable";
+ /** represents the location info tag **/
+ private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
+
+ /** where to put the events **/
+ private final MyTableModel mModel;
+ /** the number of events in the document **/
+ private int mNumEvents;
+
+ /** the time of the event **/
+ private long mTimeStamp;
+ /** the priority (level) of the event **/
+ private Level mLevel;
+ /** the category of the event **/
+ private String mCategoryName;
+ /** the NDC for the event **/
+ private String mNDC;
+ /** the thread for the event **/
+ private String mThreadName;
+ /** the msg for the event **/
+ private String mMessage;
+ /** the throwable details the event **/
+ private String[] mThrowableStrRep;
+ /** the location details for the event **/
+ private String mLocationDetails;
+ /** buffer for collecting text **/
+ private final StringBuffer mBuf = new StringBuffer();
+
+ /**
+ * Creates a new <code>XMLFileHandler</code> instance.
+ *
+ * @param aModel where to add the events
+ */
+ XMLFileHandler(MyTableModel aModel) {
+ mModel = aModel;
+ }
+
+ /** @see DefaultHandler **/
+ public void startDocument()
+ throws SAXException
+ {
+ mNumEvents = 0;
+ }
+
+ /** @see DefaultHandler **/
+ public void characters(char[] aChars, int aStart, int aLength) {
+ mBuf.append(String.valueOf(aChars, aStart, aLength));
+ }
+
+ /** @see DefaultHandler **/
+ public void endElement(String aNamespaceURI,
+ String aLocalName,
+ String aQName)
+ {
+ if (TAG_EVENT.equals(aQName)) {
+ addEvent();
+ resetData();
+ } else if (TAG_NDC.equals(aQName)) {
+ mNDC = mBuf.toString();
+ } else if (TAG_MESSAGE.equals(aQName)) {
+ mMessage = mBuf.toString();
+ } else if (TAG_THROWABLE.equals(aQName)) {
+ final StringTokenizer st =
+ new StringTokenizer(mBuf.toString(), "\n\t");
+ mThrowableStrRep = new String[st.countTokens()];
+ if (mThrowableStrRep.length > 0) {
+ mThrowableStrRep[0] = st.nextToken();
+ for (int i = 1; i < mThrowableStrRep.length; i++) {
+ mThrowableStrRep[i] = "\t" + st.nextToken();
+ }
+ }
+ }
+ }
+
+ /** @see DefaultHandler **/
+ public void startElement(String aNamespaceURI,
+ String aLocalName,
+ String aQName,
+ Attributes aAtts)
+ {
+ mBuf.setLength(0);
+
+ if (TAG_EVENT.equals(aQName)) {
+ mThreadName = aAtts.getValue("thread");
+ mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
+ mCategoryName = aAtts.getValue("logger");
+ mLevel = Level.toLevel(aAtts.getValue("level"));
+ } else if (TAG_LOCATION_INFO.equals(aQName)) {
+ mLocationDetails = aAtts.getValue("class") + "."
+ + aAtts.getValue("method")
+ + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+ + ")";
+ }
+ }
+
+ /** @return the number of events in the document **/
+ int getNumEvents() {
+ return mNumEvents;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Private methods
+ ////////////////////////////////////////////////////////////////////////////
+
+ /** Add an event to the model **/
+ private void addEvent() {
+ mModel.addEvent(new EventDetails(mTimeStamp,
+ mLevel,
+ mCategoryName,
+ mNDC,
+ mThreadName,
+ mMessage,
+ mThrowableStrRep,
+ mLocationDetails));
+ mNumEvents++;
+ }
+
+ /** Reset the data for an event **/
+ private void resetData() {
+ mTimeStamp = 0;
+ mLevel = null;
+ mCategoryName = null;
+ mNDC = null;
+ mThreadName = null;
+ mMessage = null;
+ mThrowableStrRep = null;
+ mLocationDetails = null;
+ }
+}
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png?rev=1345492&view=auto
==============================================================================
Binary file - no diff available.
Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png
------------------------------------------------------------------------------
svn:mime-type = image/png
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig?rev=1345492&view=auto
==============================================================================
Files logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig (added) and logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig Sat Jun 2 11:40:31 2012 differ
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html Sat Jun 2 11:40:31 2012
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<HTML>
+ <HEAD>
+ <TITLE>Chainsaw Tool</TITLE>
+ </head>
+
+ <BODY>
+
+ <P>Chainsaw is a GUI log viewer and filter for the log4j
+package. By default it listens for <a
+href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
+the <A href="../net/SocketAppender.html">SocketAppender</A> and
+displays them in a table. The events can be filtered based on:</P>
+
+ <UL>
+ <LI>Level </li>
+
+ <LI>Thread name</li>
+
+ <LI>Logger</li>
+ <LI>Message</li>
+
+ <LI>NDC</LI>
+ </UL>
+
+ <P>All the details for each event can be displayed by selecting
+ the event in the table.</P>
+
+ <P>Chainsaw also supports loading a events logged to a file using
+ the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
+ is great for analysing log files, and means you do not need to
+ keep Chainsaw running continously. It is easy to add support
+ for loading events from other sources like JDBC.</P>
+
+ <P>A picture is worth a thousand words: </P>
+
+ <P align=center><A
+ href="doc-files/screen_01.png"><IMG
+ height="50%" alt="Screen shot of chainsaw"
+ src="doc-files/screen_01.png"
+ width="50%"></A>.</P>
+
+ <P>Finally, why is it called chainsaw?
+ Because it cuts your log (file) down to size. :-)
+ </P>
+
+
+ <H2>Requirements</H2>
+
+ <P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
+
+
+ <H2>Running chainsaw</H2>
+
+ <H3>Setup</H3>
+ <P>You need to include the <code>log4j.jar</code> in the classpath.
+
+ <H3>Usage</H3>
+
+ <P>The command line usage is:</P>
+
+ <PRE> java -D<property>=<value> org.apache.log4j.chainsaw.Main </PRE>
+
+ <P>The default behaviour of chainsaw can be changed by setting system properties
+ using the <CODE>-D<property>=<value></CODE> arguments to java. The
+ following table describes what properties can be set:</P>
+
+ <TABLE cellSpacing=0 cellPadding=2 border=1>
+
+ <TR>
+ <TD vAlign=top><B>Property</B></TD>
+ <TD vAlign=top><B>Description</B></TD></TR>
+ <TR>
+ <TD vAlign=top>chainsaw.port</TD>
+ <TD vAlign=top>Indicates which port to listen for connections on. Defaults
+ to <SPAN class=default>"4445"</SPAN>.
+ </TD>
+ </TR>
+ </TBODY>
+ </TABLE>
+
+ <H2>Configuring Log4J</H2>
+
+ <P>You will need to configure log4j to send logging events to
+ Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
+ for sending logging events to Chainsaw.</P>
+
+<PRE>
+log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
+
+log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
+log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
+log4j.appender.CHAINSAW_CLIENT.Port=4445
+log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
+</PRE>
+
+
+
+ </body>
+</html>
\ No newline at end of file
Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig Sat Jun 2 11:40:31 2012
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<HTML>
+ <HEAD>
+ <TITLE>Chainsaw Tool</TITLE>
+ </head>
+
+ <BODY>
+
+ <P>Chainsaw is a GUI log viewer and filter for the log4j
+package. By default it listens for <a
+href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
+the <A href="../net/SocketAppender.html">SocketAppender</A> and
+displays them in a table. The events can be filtered based on:</P>
+
+ <UL>
+ <LI>Level </li>
+
+ <LI>Thread name</li>
+
+ <LI>Logger</li>
+ <LI>Message</li>
+
+ <LI>NDC</LI>
+ </UL>
+
+ <P>All the details for each event can be displayed by selecting
+ the event in the table.</P>
+
+ <P>Chainsaw also supports loading a events logged to a file using
+ the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
+ is great for analysing log files, and means you do not need to
+ keep Chainsaw running continously. It is easy to add support
+ for loading events from other sources like JDBC.</P>
+
+ <P>A picture is worth a thousand words: </P>
+
+ <P align=center><A
+ href="doc-files/screen_01.png"><IMG
+ height="50%" alt="Screen shot of chainsaw"
+ src="doc-files/screen_01.png"
+ width="50%"></A>.</P>
+
+ <P>Finally, why is it called chainsaw?
+ Because it cuts your log (file) down to size. :-)
+ </P>
+
+
+ <H2>Requirements</H2>
+
+ <P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
+
+
+ <H2>Running chainsaw</H2>
+
+ <H3>Setup</H3>
+ <P>You need to include the <code>log4j.jar</code> in the classpath.
+
+ <H3>Usage</H3>
+
+ <P>The command line usage is:</P>
+
+ <PRE> java -D<property>=<value> org.apache.log4j.chainsaw.Main </PRE>
+
+ <P>The default behaviour of chainsaw can be changed by setting system properties
+ using the <CODE>-D<property>=<value></CODE> arguments to java. The
+ following table describes what properties can be set:</P>
+
+ <TABLE cellSpacing=0 cellPadding=2 border=1>
+
+ <TR>
+ <TD vAlign=top><B>Property</B></TD>
+ <TD vAlign=top><B>Description</B></TD></TR>
+ <TR>
+ <TD vAlign=top>chainsaw.port</TD>
+ <TD vAlign=top>Indicates which port to listen for connections on. Defaults
+ to <SPAN class=default>"4445"</SPAN>.
+ </TD>
+ </TR>
+ </TBODY>
+ </TABLE>
+
+ <H2>Configuring Log4J</H2>
+
+ <P>You will need to configure log4j to send logging events to
+ Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
+ for sending logging events to Chainsaw.</P>
+
+<PRE>
+log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
+
+log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
+log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
+log4j.appender.CHAINSAW_CLIENT.Port=4445
+log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
+</PRE>
+
+
+
+ </body>
+</html>
\ No newline at end of file
Copied: logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS (from r1345481, logging/log4j/branches/log4j12modules/contribs/CONTENTS)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS?p2=logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS&p1=logging/log4j/branches/log4j12modules/contribs/CONTENTS&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Added: logging/log4j/branches/log4j12modules/modules/contribs/pom.xml
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/pom.xml?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/contribs/pom.xml (added)
+++ logging/log4j/branches/log4j12modules/modules/contribs/pom.xml Sat Jun 2 11:40:31 2012
@@ -0,0 +1,60 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.log4j</groupId>
+ <artifactId>log4j-modules</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.apache.log4j</groupId>
+ <artifactId>log4j-contribs</artifactId>
+ <name>Apache Log4j-Contribtutions</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.log4j</groupId>
+ <artifactId>log4j-net</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ <type>bundle</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.0.1</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>org.apache.log4j.contribs.*</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
Propchange: logging/log4j/branches/log4j12modules/modules/contribs/pom.xml
------------------------------------------------------------------------------
svn:eol-style = native
Added: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java (added)
+++ logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java Sat Jun 2 11:40:31 2012
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import java.io.*;
+import org.apache.log4j.*;
+
+
+/**
+ * An OutputStream that flushes out to a Category.<p>
+ *
+ * Note that no data is written out to the Category until the stream is
+ * flushed or closed.<p>
+ *
+ * Example:<pre>
+ * // make sure everything sent to System.err is logged
+ * System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.WARN), true));
+ *
+ * // make sure everything sent to System.out is also logged
+ * System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.INFO), true));
+ * </pre>
+ *
+ * @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
+ * @see Category
+ */
+public class LoggingOutputStream extends OutputStream {
+ protected static final String LINE_SEPERATOR = System.getProperty("line.separator");
+
+
+ /**
+ * Used to maintain the contract of {@link #close()}.
+ */
+ protected boolean hasBeenClosed = false;
+
+ /**
+ * The internal buffer where data is stored.
+ */
+ protected byte[] buf;
+
+ /**
+ * The number of valid bytes in the buffer. This value is always
+ * in the range <tt>0</tt> through <tt>buf.length</tt>; elements
+ * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
+ * byte data.
+ */
+ protected int count;
+
+
+ /**
+ * Remembers the size of the buffer for speed.
+ */
+ private int bufLength;
+
+ /**
+ * The default number of bytes in the buffer. =2048
+ */
+ public static final int DEFAULT_BUFFER_LENGTH = 2048;
+
+
+ /**
+ * The category to write to.
+ */
+ protected Category category;
+
+ /**
+ * The priority to use when writing to the Category.
+ */
+ protected Priority priority;
+
+
+ private LoggingOutputStream() {
+ // illegal
+ }
+
+
+ /**
+ * Creates the LoggingOutputStream to flush to the given Category.
+ *
+ * @param cat the Category to write to
+ *
+ * @param priority the Priority to use when writing to the Category
+ *
+ * @exception IllegalArgumentException
+ * if cat == null or priority == null
+ */
+ public LoggingOutputStream(Category cat, Priority priority)
+ throws IllegalArgumentException {
+ if (cat == null) {
+ throw new IllegalArgumentException("cat == null");
+ }
+ if (priority == null) {
+ throw new IllegalArgumentException("priority == null");
+ }
+
+ this.priority = priority;
+ category = cat;
+ bufLength = DEFAULT_BUFFER_LENGTH;
+ buf = new byte[DEFAULT_BUFFER_LENGTH];
+ count = 0;
+ }
+
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream. The general contract of <code>close</code>
+ * is that it closes the output stream. A closed stream cannot perform
+ * output operations and cannot be reopened.
+ */
+ public void close() {
+ flush();
+ hasBeenClosed = true;
+ }
+
+
+ /**
+ * Writes the specified byte to this output stream. The general
+ * contract for <code>write</code> is that one byte is written
+ * to the output stream. The byte to be written is the eight
+ * low-order bits of the argument <code>b</code>. The 24
+ * high-order bits of <code>b</code> are ignored.
+ *
+ * @param b the <code>byte</code> to write
+ *
+ * @exception IOException
+ * if an I/O error occurs. In particular,
+ * an <code>IOException</code> may be thrown if the
+ * output stream has been closed.
+ */
+ public void write(final int b) throws IOException {
+ if (hasBeenClosed) {
+ throw new IOException("The stream has been closed.");
+ }
+
+ // don't log nulls
+ if (b == 0) {
+ return;
+ }
+
+ // would this be writing past the buffer?
+ if (count == bufLength) {
+ // grow the buffer
+ final int newBufLength = bufLength+DEFAULT_BUFFER_LENGTH;
+ final byte[] newBuf = new byte[newBufLength];
+
+ System.arraycopy(buf, 0, newBuf, 0, bufLength);
+
+ buf = newBuf;
+ bufLength = newBufLength;
+ }
+
+ buf[count] = (byte)b;
+ count++;
+ }
+
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out. The general contract of <code>flush</code> is
+ * that calling it is an indication that, if any bytes previously
+ * written have been buffered by the implementation of the output
+ * stream, such bytes should immediately be written to their
+ * intended destination.
+ */
+ public void flush() {
+ if (count == 0) {
+ return;
+ }
+
+ // don't print out blank lines; flushing from PrintStream puts out these
+ if (count == LINE_SEPERATOR.length()) {
+ if ( ((char)buf[0]) == LINE_SEPERATOR.charAt(0) &&
+ ( ( count == 1 ) || // <- Unix & Mac, -> Windows
+ ( (count == 2) && ((char)buf[1]) == LINE_SEPERATOR.charAt(1) ) ) ) {
+ reset();
+ return;
+ }
+ }
+
+ final byte[] theBytes = new byte[count];
+
+ System.arraycopy(buf, 0, theBytes, 0, count);
+
+ category.log(priority, new String(theBytes));
+
+ reset();
+ }
+
+
+ private void reset() {
+ // not resetting the buffer -- assuming that if it grew that it
+ // will likely grow similarly again
+ count = 0;
+ }
+
+}
+
Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18 (from r1345481, logging/log4j/branches/log4j12modules/contribs/EirikLygre/mail-2001-01-18)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18&p1=logging/log4j/branches/log4j12modules/contribs/EirikLygre/mail-2001-01-18&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JamesHouse/mail-2001-01-23)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23&p1=logging/log4j/branches/log4j12modules/contribs/JamesHouse/mail-2001-01-23&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20 (from r1345481, logging/log4j/branches/log4j12modules/contribs/Jamie Tsao/mail-2001-06-20)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20&p1=logging/log4j/branches/log4j12modules/contribs/Jamie%20Tsao/mail-2001-06-20&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1326)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1326&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1454)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1454&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-13T0646)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-13T0646&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01 (from r1345481, logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2001-02-01)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01&p1=logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2001-02-01&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt (from r1345481, logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2002-03-27.txt)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt&p1=logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2002-03-27.txt&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)
Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07 (from r1345481, logging/log4j/branches/log4j12modules/contribs/KitchingSimon/mail-2001-02-07)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07&p1=logging/log4j/branches/log4j12modules/contribs/KitchingSimon/mail-2001-02-07&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
(empty)