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 }