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