You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@logging.apache.org by sd...@apache.org on 2010/11/05 09:26:33 UTC

svn commit: r1031469 - in /logging/chainsaw/trunk/src/main: java/org/apache/log4j/chainsaw/ resources/org/apache/log4j/chainsaw/help/

Author: sdeboy
Date: Fri Nov  5 08:26:33 2010
New Revision: 1031469

URL: http://svn.apache.org/viewvc?rev=1031469&view=rev
Log:
Added ability to create log file receiver configurations from log4j xml configuration fileappender entries

Parses the xml configuration and the patternLayout and date specifiers and creates LogFilePatternReceiver entries

Modified:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java?rev=1031469&r1=1031468&r2=1031469&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java Fri Nov  5 08:26:33 2010
@@ -16,13 +16,23 @@
  */
 package org.apache.log4j.chainsaw;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.FileAppender;
 import org.apache.log4j.helpers.OptionConverter;
 import org.apache.log4j.pattern.ClassNamePatternConverter;
+import org.apache.log4j.pattern.DatePatternConverter;
 import org.apache.log4j.pattern.FileLocationPatternConverter;
 import org.apache.log4j.pattern.FullLocationPatternConverter;
 import org.apache.log4j.pattern.LevelPatternConverter;
@@ -39,6 +49,14 @@ import org.apache.log4j.pattern.Properti
 import org.apache.log4j.pattern.RelativeTimePatternConverter;
 import org.apache.log4j.pattern.SequenceNumberPatternConverter;
 import org.apache.log4j.pattern.ThreadPatternConverter;
+import org.apache.log4j.xml.Log4jEntityResolver;
+import org.apache.log4j.xml.SAXErrorHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
 
 public class LogFilePatternLayoutBuilder
 {
@@ -52,11 +70,39 @@ public class LogFilePatternLayoutBuilder
         return getFormatFromConverters(converters);
     }
 
+    public static String getTimeStampFormat(String patternLayout) {
+      int basicIndex = patternLayout.indexOf("%d");
+      if (basicIndex < 0) {
+        return null;
+      }
+
+      int index = patternLayout.indexOf("%d{");
+      //%d - default
+      if (index < 0) {
+        return "yyyy-MM-dd HH:mm:ss,SSS";
+      }
+
+      int length = patternLayout.substring(index).indexOf("}");
+      String timestampFormat = patternLayout.substring(index + "%d{".length(), index + length);
+      if (timestampFormat.equals("ABSOLUTE")) {
+        return "HH:mm:ss,SSS";
+      }
+      if (timestampFormat.equals("ISO8601")) {
+        return "yyyy-MM-dd HH:mm:ss,SSS";
+      }
+      if (timestampFormat.equals("DATE")) {
+        return "dd MMM yyyy HH:mm:ss,SSS";
+      }
+      return timestampFormat;
+    }
+  
     private static String getFormatFromConverters(List converters) {
         StringBuffer buffer = new StringBuffer();
         for (Iterator iter = converters.iterator();iter.hasNext();) {
             LoggingEventPatternConverter converter = (LoggingEventPatternConverter)iter.next();
-            if (converter instanceof MessagePatternConverter) {
+            if (converter instanceof DatePatternConverter) {
+              buffer.append("TIMESTAMP");
+            } else if (converter instanceof MessagePatternConverter) {
                 buffer.append("MESSAGE");
             } else if (converter instanceof LoggerPatternConverter) {
                 buffer.append("LOGGER");
@@ -98,4 +144,74 @@ public class LogFilePatternLayoutBuilder
         }
         return buffer.toString();
     }
+
+  public static Map getAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
+    InputStream stream = file.toURI().toURL().openStream();
+    Map result = new HashMap();
+    try {
+      InputSource src = new InputSource(stream);
+      src.setSystemId(file.toURI().toURL().toString());
+      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+      DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new Log4jEntityResolver());
+      Document doc = docBuilder.parse(src);
+      NodeList appenders = doc.getElementsByTagName("appender");
+      for (int i = 0; i < appenders.getLength(); i++) {
+        Node appender = appenders.item(i);
+        NamedNodeMap appenderAttributes = appender.getAttributes();
+//        Class appenderClass = Class.forName(map.getNamedItem("class").getNodeValue());
+        Node appenderClass = appenderAttributes.getNamedItem("class");
+        try {
+          if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
+            //load the class or try to support custom subclasses that we don't have available in the classpath but end in 'FileAppender'
+            if (appenderClass.getNodeValue().toLowerCase().endsWith("fileappender") || FileAppender.class.isAssignableFrom(Class.forName(appenderClass.getNodeValue()))) {
+              String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
+              //subclass of FileAppender - add it
+              Map entry = new HashMap();
+              NodeList appenderChildren = appender.getChildNodes();
+              for (int j = 0; j < appenderChildren.getLength(); j++) {
+                Node appenderChild = appenderChildren.item(j);
+                if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
+                  Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
+                  if (fileNameNode != null && fileNameNode.getNodeValue().equals("file")) {
+                    Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
+                    if (fileValueNode != null) {
+                      entry.put("file", fileValueNode.getNodeValue());
+                    }
+                  }
+                }
+                if (appenderChild.getNodeName().equals("layout") && appenderChild.hasAttributes()) {
+                  NamedNodeMap layoutAttributes = appenderChild.getAttributes();
+                  Node layoutNode = layoutAttributes.getNamedItem("class");
+                  if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
+                    NodeList layoutChildren = appenderChild.getChildNodes();
+                    for (int k = 0; k < layoutChildren.getLength(); k++) {
+                      Node layoutChild = layoutChildren.item(k);
+                      if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
+                        Node layoutName = layoutChild.getAttributes().getNamedItem("name");
+                        if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equals("ConversionPattern")) {
+                          Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
+                          if (conversionValue != null) {
+                            entry.put("conversion", conversionValue.getNodeValue());
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+              result.put(appenderName, entry);
+            }
+          }
+        } catch (Exception e) {
+          e.printStackTrace();
+        }
+      }
+    } finally {
+      stream.close();
+    }
+    return result;
+  }
 }

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java?rev=1031469&r1=1031468&r2=1031469&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java Fri Nov  5 08:26:33 2010
@@ -84,6 +84,7 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.EventListenerList;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.AppenderSkeleton;
@@ -126,6 +127,7 @@ import org.apache.log4j.spi.LoggingEvent
 import org.apache.log4j.spi.RepositorySelector;
 import org.apache.log4j.xml.DOMConfigurator;
 import org.apache.log4j.xml.XMLDecoder;
+import org.xml.sax.SAXException;
 
 
 /**
@@ -1459,6 +1461,47 @@ public class LogUI extends JFrame implem
                 MessageCenter.getInstance().getLogger().info(
                   "An error occurred creating your Receiver");
               }
+            } else if (receiverConfigurationPanel.getModel().isLog4jConfig()) {
+              File log4jConfigFile = receiverConfigurationPanel.getModel().getLog4jConfigFile();
+              if (log4jConfigFile != null) {
+                try {
+                  Map entries = LogFilePatternLayoutBuilder.getAppenderConfiguration(log4jConfigFile);
+                  for (Iterator iter = entries.entrySet().iterator();iter.hasNext();) {
+                    try {
+                      Map.Entry entry = (Map.Entry)iter.next();
+                      String name = (String) entry.getKey();
+                      Map values = (Map) entry.getValue();
+                      //values: conversion, file
+                      String conversionPattern = values.get("conversion").toString();
+                      File file = new File(values.get("file").toString());
+                      URL fileURL = file.toURI().toURL();
+                      String timestampFormat = LogFilePatternLayoutBuilder.getTimeStampFormat(conversionPattern);
+                      String receiverPattern = LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(conversionPattern);
+                      VFSLogFilePatternReceiver fileReceiver = new VFSLogFilePatternReceiver();
+                      fileReceiver.setName(name);
+                      fileReceiver.setAutoReconnect(true);
+                      fileReceiver.setContainer(LogUI.this);
+                      fileReceiver.setAppendNonMatches(true);
+                      fileReceiver.setFileURL(fileURL.toURI().toString());
+                      fileReceiver.setTailing(true);
+                      fileReceiver.setLogFormat(receiverPattern);
+                      fileReceiver.setTimestampFormat(timestampFormat);
+                      fileReceiver.setThreshold(Level.TRACE);
+                      pluginRegistry.addPlugin(fileReceiver);
+                      fileReceiver.activateOptions();
+                      receiversPanel.updateReceiverTreeInDispatchThread();
+                    } catch (URISyntaxException e1) {
+                      e1.printStackTrace();
+                    }
+                  }
+                } catch (IOException e1) {
+                  e1.printStackTrace();
+                } catch (ParserConfigurationException e1) {
+                  e1.printStackTrace();
+                } catch (SAXException e1) {
+                  e1.printStackTrace();
+                }
+              }
             } else if (receiverConfigurationPanel.getModel().isLoadConfig()) {
                   configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
             } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java?rev=1031469&r1=1031468&r2=1031469&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java Fri Nov  5 08:26:33 2010
@@ -30,6 +30,7 @@ import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.io.File;
 import java.net.MalformedURLException;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 
@@ -74,6 +75,10 @@ class ReceiverConfigurationPanel extends
     private DefaultComboBoxModel networkReceiverClassNameComboBoxModel;
     private DefaultComboBoxModel networkReceiverPortComboBoxModel;
 
+    //log4j config receiver widgets
+    private JButton browseLog4jConfigButton;
+    private JTextField log4jConfigURLTextField;
+
     //logfile receiver widgets
     private JButton browseLogFileButton;
     private JComboBox logFileFormatTypeComboBox;
@@ -97,6 +102,7 @@ class ReceiverConfigurationPanel extends
     private JButton cancelButton;
 
     //radiobutton widgets
+    private JRadioButton log4jConfigReceiverRadioButton;
     private JRadioButton logFileReceiverRadioButton;
     private JRadioButton networkReceiverRadioButton;
     private JRadioButton useExistingConfigurationRadioButton;
@@ -106,6 +112,7 @@ class ReceiverConfigurationPanel extends
 
     private final JPanel networkReceiverPanel = buildNetworkReceiverPanel();
     private final JPanel logFileReceiverPanel = buildLogFileReceiverPanel();
+    private final JPanel log4jConfigReceiverPanel = buildLog4jConfigReceiverPanel();
     private final JPanel useExistingConfigurationPanel = buildUseExistingConfigurationPanel();
     private final JPanel dontWarnAndOKPanel = buildDontWarnAndOKPanel();
     private final JPanel bottomDescriptionPanel = buildBottomDescriptionPanel();
@@ -140,6 +147,14 @@ class ReceiverConfigurationPanel extends
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
+        log4jConfigReceiverRadioButton = new JRadioButton(" Use log4j.xml fileappender configuration ");
+        buttonGroup.add(log4jConfigReceiverRadioButton);
+        add(log4jConfigReceiverRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = yPos++;
+        c.fill = GridBagConstraints.HORIZONTAL;
         networkReceiverRadioButton = new JRadioButton(" Receive events from the network ");
         buttonGroup.add(networkReceiverRadioButton);
         add(networkReceiverRadioButton, c);
@@ -185,6 +200,7 @@ class ReceiverConfigurationPanel extends
             };
 
         logFileReceiverRadioButton.addActionListener(al);
+        log4jConfigReceiverRadioButton.addActionListener(al);
         networkReceiverRadioButton.addActionListener(al);
         useExistingConfigurationRadioButton.addActionListener(al);
 
@@ -332,6 +348,52 @@ class ReceiverConfigurationPanel extends
         return panel;
     }
 
+    private JPanel buildLog4jConfigReceiverPanel() {
+        log4jConfigURLTextField = new JTextField();
+        browseLog4jConfigButton = new JButton(new AbstractAction(" Open File... ") {
+                    public void actionPerformed(ActionEvent e) {
+                        try {
+
+                            URL url = browseConfig();
+
+                            if (url != null) {
+                                log4jConfigURLTextField.setText(url.toExternalForm());
+                            }
+                        } catch (Exception ex) {
+                            logger.error(
+                                "Error browsing for log4j config file", ex);
+                        }
+                    }
+                });
+
+        browseLog4jConfigButton.setToolTipText(
+            "Shows a File Open dialog to allow you to find a log4j configuration file");
+        JPanel panel = new JPanel(new GridBagLayout());
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.gridwidth = 2;
+        c.anchor = GridBagConstraints.LINE_START;
+        c.insets = new Insets(0, 0, 5, 0);
+        panel.add(browseLog4jConfigButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 1;
+        c.insets = new Insets(0, 5, 0, 5);
+        panel.add(new JLabel(" log4j configuration file URL "), c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 1;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(log4jConfigURLTextField, c);
+
+
+        return panel;
+    }
+
     private JPanel buildLogFileReceiverPanel() {
         JPanel panel = new JPanel(new GridBagLayout());
         browseLogFileButton = new JButton(new AbstractAction(" Open File... ") {
@@ -566,6 +628,9 @@ class ReceiverConfigurationPanel extends
         if (component == logFileReceiverRadioButton) {
             lowerPanel.add(logFileReceiverPanel, BorderLayout.NORTH);
         }
+        if (component == log4jConfigReceiverRadioButton) {
+            lowerPanel.add(log4jConfigReceiverPanel, BorderLayout.NORTH);
+        }
         lowerPanel.revalidate();
         lowerPanel.repaint();
     }
@@ -683,6 +748,10 @@ class ReceiverConfigurationPanel extends
             return !cancelled && logFileReceiverRadioButton.isSelected();
         }
 
+        boolean isLog4jConfig() {
+            return !cancelled && log4jConfigReceiverRadioButton.isSelected();
+        }
+
         URL getConfigToLoad() {
 
             try
@@ -767,5 +836,17 @@ class ReceiverConfigurationPanel extends
         public boolean isCancelled() {
           return cancelled;
         }
+
+    public File getLog4jConfigFile() {
+      try {
+        URL newConfigurationURL = new URL(log4jConfigURLTextField.getText());
+        return new File(newConfigurationURL.toURI());
+      } catch (URISyntaxException e) {
+        e.printStackTrace();
+      } catch (MalformedURLException e) {
+        e.printStackTrace();
+      }
+      return null;
+    }
   }
 }

Modified: logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html?rev=1031469&r1=1031468&r2=1031469&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html (original)
+++ logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html Fri Nov  5 08:26:33 2010
@@ -10,6 +10,11 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>5 Nov 2010</h2>
+<ul>
+<li>Added ability to create log file receiver configurations from log4j xml configuration fileappender entries</li>
+<li>Added ability to save the receiver configuration from the receiver modification panel</li>
+</ul>
 <h2>4 Nov 2010</h2>
 <ul>
 <li>Added ability to save the receiver configuration defined through the initial receiver configuration panel with a user-specified file path and name</li>