View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.log4j.chainsaw;
    18
    19  import java.io.File;
    20  import java.io.FileInputStream;
    21  import java.io.IOException;
    22  import java.io.InputStream;
    23  import java.util.ArrayList;
    24  import java.util.Enumeration;
    25  import java.util.HashMap;
    26  import java.util.Iterator;
    27  import java.util.List;
    28  import java.util.Locale;
    29  import java.util.Map;
    30  import java.util.Properties;
    31
    32  import javax.xml.parsers.DocumentBuilder;
    33  import javax.xml.parsers.DocumentBuilderFactory;
    34  import javax.xml.parsers.ParserConfigurationException;
    35
    36  import org.apache.log4j.chainsaw.messages.MessageCenter;
    37  import org.apache.log4j.helpers.OptionConverter;
    38  import org.apache.log4j.pattern.ClassNamePatternConverter;
    39  import org.apache.log4j.pattern.DatePatternConverter;
    40  import org.apache.log4j.pattern.FileLocationPatternConverter;
    41  import org.apache.log4j.pattern.FullLocationPatternConverter;
    42  import org.apache.log4j.pattern.LevelPatternConverter;
    43  import org.apache.log4j.pattern.LineLocationPatternConverter;
    44  import org.apache.log4j.pattern.LineSeparatorPatternConverter;
    45  import org.apache.log4j.pattern.LiteralPatternConverter;
    46  import org.apache.log4j.pattern.LoggerPatternConverter;
    47  import org.apache.log4j.pattern.LoggingEventPatternConverter;
    48  import org.apache.log4j.pattern.MessagePatternConverter;
    49  import org.apache.log4j.pattern.MethodLocationPatternConverter;
    50  import org.apache.log4j.pattern.NDCPatternConverter;
    51  import org.apache.log4j.pattern.PatternParser;
    52  import org.apache.log4j.pattern.PropertiesPatternConverter;
    53  import org.apache.log4j.pattern.RelativeTimePatternConverter;
    54  import org.apache.log4j.pattern.SequenceNumberPatternConverter;
    55  import org.apache.log4j.pattern.ThreadPatternConverter;
    56  import org.apache.log4j.xml.Log4jEntityResolver;
    57  import org.apache.log4j.xml.SAXErrorHandler;
    58  import org.w3c.dom.Document;
    59  import org.w3c.dom.NamedNodeMap;
    60  import org.w3c.dom.Node;
    61  import org.w3c.dom.NodeList;
    62  import org.xml.sax.InputSource;
    63  import org.xml.sax.SAXException;
    64
    65  public class LogFilePatternLayoutBuilder
    66  {
    67      public static String getLogFormatFromPatternLayout(String patternLayout) {
    68          String input = OptionConverter.convertSpecialChars(patternLayout);
    69          List converters = new ArrayList();
    70          List fields = new ArrayList();
    71          Map converterRegistry = null;
    72
    73          PatternParser.parse(input, converters, fields, converterRegistry, PatternParser.getPatternLayoutRules());
    74          return getFormatFromConverters(converters);
    75      }
    76
    77      public static String getTimeStampFormat(String patternLayout) {
    78        int basicIndex = patternLayout.indexOf("%d");
    79        if (basicIndex < 0) {
    80          return null;
    81        }
    82
    83        int index = patternLayout.indexOf("%d{");
    84        //%d - default
    85        if (index < 0) {
    86          return "yyyy-MM-dd HH:mm:ss,SSS";
    87        }
    88
    89        int length = patternLayout.substring(index).indexOf("}");
    90        String timestampFormat = patternLayout.substring(index + "%d{".length(), index + length);
    91        if (timestampFormat.equals("ABSOLUTE")) {
    92          return "HH:mm:ss,SSS";
    93        }
    94        if (timestampFormat.equals("ISO8601")) {
    95          return "yyyy-MM-dd HH:mm:ss,SSS";
    96        }
    97        if (timestampFormat.equals("DATE")) {
    98          return "dd MMM yyyy HH:mm:ss,SSS";
    99        }
    100       return timestampFormat;
    101     }
    102
    103     private static String getFormatFromConverters(List converters) {
    104         StringBuffer buffer = new StringBuffer();
    105         for (Iterator iter = converters.iterator();iter.hasNext();) {
    106             LoggingEventPatternConverter converter = (LoggingEventPatternConverter)iter.next();
    107             if (converter instanceof DatePatternConverter) {
    108               buffer.append("TIMESTAMP");
    109             } else if (converter instanceof MessagePatternConverter) {
    110                 buffer.append("MESSAGE");
    111             } else if (converter instanceof LoggerPatternConverter) {
    112                 buffer.append("LOGGER");
    113             } else if (converter instanceof ClassNamePatternConverter) {
    114                 buffer.append("CLASS");
    115             } else if (converter instanceof RelativeTimePatternConverter) {
    116                 buffer.append("PROP(RELATIVETIME)");
    117             } else if (converter instanceof ThreadPatternConverter) {
    118                 buffer.append("THREAD");
    119             } else if (converter instanceof NDCPatternConverter) {
    120                 buffer.append("NDC");
    121             } else if (converter instanceof LiteralPatternConverter) {
    122                 LiteralPatternConverter literal = (LiteralPatternConverter)converter;
    123                 //format shouldn't normally take a null, but we're getting a literal, so passing in the buffer will work
    124                 literal.format(null, buffer);
    125             } else if (converter instanceof SequenceNumberPatternConverter) {
    126                 buffer.append("PROP(log4jid)");
    127             } else if (converter instanceof LevelPatternConverter) {
    128                 buffer.append("LEVEL");
    129             } else if (converter instanceof MethodLocationPatternConverter) {
    130                 buffer.append("METHOD");
    131             } else if (converter instanceof FullLocationPatternConverter) {
    132                 buffer.append("PROP(locationInfo)");
    133             } else if (converter instanceof LineLocationPatternConverter) {
    134                 buffer.append("LINE");
    135             } else if (converter instanceof FileLocationPatternConverter) {
    136                 buffer.append("FILE");
    137             } else if (converter instanceof PropertiesPatternConverter) {
    138 //                PropertiesPatternConverter propertiesConverter = (PropertiesPatternConverter) converter;
    139 //                String option = propertiesConverter.getOption();
    140 //                if (option != null && option.length() > 0) {
    141 //                    buffer.append("PROP(" + option + ")");
    142 //                } else {
    143                     buffer.append("PROP(PROPERTIES)");
    144 //                }
    145             } else if (converter instanceof LineSeparatorPatternConverter) {
    146                 //done
    147             }
    148         }
    149         return buffer.toString();
    150     }
    151
    152   public static Map getAppenderConfiguration(File file) {
    153     try {
    154       return getXMLFileAppenderConfiguration(file);
    155     } catch (IOException e) {
    156       //ignore
    157     } catch (ParserConfigurationException e) {
    158       //ignore
    159     } catch (SAXException e) {
    160       //ignore
    161     }
    162     try {
    163       return getPropertiesFileAppenderConfiguration(file);
    164     } catch (Exception e) {
    165       //ignore
    166     }
    167     //don't return null
    168     return new HashMap();
    169   }
    170
    171   public static Map getPropertiesFileAppenderConfiguration(File propertyFile) throws IOException, ParserConfigurationException, SAXException {
    172     Map result = new HashMap();
    173     String appenderPrefix = "log4j.appender";
    174     Properties props = new Properties();
    175     FileInputStream inputStream = null;
    176     try {
    177       inputStream = new FileInputStream(propertyFile);
    178       props.load(inputStream);
    179       Enumeration propertyNames = props.propertyNames();
    180       Map appenders = new HashMap();
    181       while (propertyNames.hasMoreElements()) {
    182         String propertyName = propertyNames.nextElement().toString();
    183         if (propertyName.startsWith(appenderPrefix)) {
    184           String value = propertyName.substring(appenderPrefix.length() + 1);
    185           if (value.indexOf(".") == -1) {
    186             //no sub-values - this entry is the appender name & class
    187             appenders.put(value, props.getProperty(propertyName).trim());
    188           }
    189         }
    190       }
    191       for (Iterator iter = appenders.entrySet().iterator();iter.hasNext();) {
    192         Map.Entry appenderEntry = (Map.Entry)iter.next();
    193         String appenderName = appenderEntry.getKey().toString();
    194         String appenderClassName = appenderEntry.getValue().toString();
    195         if (appenderClassName.toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
    196           String layout = props.getProperty(appenderPrefix + "." + appenderName + ".layout");
    197           if (layout != null && layout.trim().equals("org.apache.log4j.PatternLayout")) {
    198             String conversion = props.getProperty(appenderPrefix + "." + appenderName + ".layout.ConversionPattern");
    199             String file = props.getProperty(appenderPrefix + "." + appenderName + ".File");
    200             if (conversion != null && file != null) {
    201               Map entry = new HashMap();
    202               entry.put("file", file.trim());
    203               entry.put("conversion", conversion.trim());
    204               result.put(appenderName, entry);
    205             }
    206           }
    207         }
    208       }
    209           /*
    210           example:
    211           log4j.appender.R=org.apache.log4j.RollingFileAppender
    212           log4j.appender.R.File=${catalina.base}/logs/tomcat.log
    213           log4j.appender.R.MaxFileSize=10MB
    214           log4j.appender.R.MaxBackupIndex=10
    215           log4j.appender.R.layout=org.apache.log4j.PatternLayout
    216           log4j.appender.R.layout.ConversionPattern=%d - %p %t %c - %m%n
    217            */
    218     }
    219     catch (IOException ioe) {
    220     }
    221     finally {
    222       if (inputStream != null) {
    223         inputStream.close();
    224       }
    225     }
    226     //don't return null
    227     return result;
    228   }
    229
    230   private static Map getXMLFileAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
    231     InputStream stream = file.toURI().toURL().openStream();
    232     Map result = new HashMap();
    233     try {
    234       InputSource src = new InputSource(stream);
    235       src.setSystemId(file.toURI().toURL().toString());
    236       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    237       DocumentBuilder docBuilder = dbf.newDocumentBuilder();
    238
    239       docBuilder.setErrorHandler(new SAXErrorHandler());
    240       docBuilder.setEntityResolver(new Log4jEntityResolver());
    241       Document doc = docBuilder.parse(src);
    242       NodeList appenders = doc.getElementsByTagName("appender");
    243       for (int i = 0; i < appenders.getLength(); i++) {
    244         Node appender = appenders.item(i);
    245         NamedNodeMap appenderAttributes = appender.getAttributes();
    246 //        Class appenderClass = Class.forName(map.getNamedItem("class").getNodeValue());
    247         Node appenderClass = appenderAttributes.getNamedItem("class");
    248         if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
    249           //all log4j fileappenders end in fileappender..if a custom fileappender also ends in fileappender and uses the same dom nodes to be loaded,
    250           //try to parse the nodes as well
    251           if (appenderClass.getNodeValue().toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
    252             String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
    253             //subclass of FileAppender - add it
    254             Map entry = new HashMap();
    255             NodeList appenderChildren = appender.getChildNodes();
    256             for (int j = 0; j < appenderChildren.getLength(); j++) {
    257               Node appenderChild = appenderChildren.item(j);
    258               if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
    259                 Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
    260                 if (fileNameNode != null && fileNameNode.getNodeValue().equalsIgnoreCase("file")) {
    261                   Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
    262                   if (fileValueNode != null) {
    263                     entry.put("file", fileValueNode.getNodeValue());
    264                   }
    265                 }
    266               }
    267               if (appenderChild.getNodeName().equalsIgnoreCase("layout") && appenderChild.hasAttributes()) {
    268                 NamedNodeMap layoutAttributes = appenderChild.getAttributes();
    269                 Node layoutNode = layoutAttributes.getNamedItem("class");
    270                 if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equalsIgnoreCase("org.apache.log4j.PatternLayout")) {
    271                   NodeList layoutChildren = appenderChild.getChildNodes();
    272                   for (int k = 0; k < layoutChildren.getLength(); k++) {
    273                     Node layoutChild = layoutChildren.item(k);
    274                     if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
    275                       Node layoutName = layoutChild.getAttributes().getNamedItem("name");
    276                       if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equalsIgnoreCase("conversionpattern")) {
    277                         Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
    278                         if (conversionValue != null) {
    279                           entry.put("conversion", conversionValue.getNodeValue());
    280                         }
    281                       }
    282                     }
    283                   }
    284                 }
    285               }
    286             }
    287             result.put(appenderName, entry);
    288           }
    289         }
    290       }
    291     } finally {
    292       stream.close();
    293     }
    294     MessageCenter.getInstance().getLogger().info("getXMLFileAppenderConfiguration for file: " + file + ", result: " + result);
    295     return result;
    296   }
    297 }