blob: da4eac4bacef253e7a3876ec8c4907c02be371ea [file] [log] [blame]
/*
* 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.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.chainsaw.messages.MessageCenter;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.pattern.*;
import org.apache.log4j.xml.SAXErrorHandler;
import org.apache.logging.log4j.core.util.OptionConverter;
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
{
public static String getLogFormatFromPatternLayout(String patternLayout) {
String input = OptionConverter.convertSpecialChars(patternLayout);
List<PatternConverter> converters = new ArrayList<>();
List<FormattingInfo> fields = new ArrayList<>();
new PatternParser(PatternLayout.KEY).parse(input, converters, fields, false, false);
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<PatternConverter> converters) {
StringBuilder buffer = new StringBuilder();
for (PatternConverter converter : converters) {
if (converter instanceof DatePatternConverter) {
buffer.append("TIMESTAMP");
} else if (converter instanceof MessagePatternConverter) {
buffer.append("MESSAGE");
} else if (converter instanceof LoggerPatternConverter) {
buffer.append("LOGGER");
} else if (converter instanceof ClassNamePatternConverter) {
buffer.append("CLASS");
} else if (converter instanceof RelativeTimePatternConverter) {
buffer.append("PROP(RELATIVETIME)");
} else if (converter instanceof ThreadNamePatternConverter) {
buffer.append("THREAD");
} else if (converter instanceof NdcPatternConverter) {
buffer.append("NDC");
} else if (converter instanceof LiteralPatternConverter) {
LiteralPatternConverter literal = (LiteralPatternConverter)converter;
//format shouldn't normally take a null, but we're getting a literal, so passing in the buffer will work
literal.format(buffer);
} else if (converter instanceof SequenceNumberPatternConverter) {
buffer.append("PROP(log4jid)");
} else if (converter instanceof LevelPatternConverter) {
buffer.append("LEVEL");
} else if (converter instanceof MethodLocationPatternConverter) {
buffer.append("METHOD");
} else if (converter instanceof FullLocationPatternConverter) {
buffer.append("PROP(locationInfo)");
} else if (converter instanceof LineLocationPatternConverter) {
buffer.append("LINE");
} else if (converter instanceof FileLocationPatternConverter) {
buffer.append("FILE");
} else if (converter instanceof MdcPatternConverter) {
// PropertiesPatternConverter propertiesConverter = (PropertiesPatternConverter) converter;
// String option = propertiesConverter.getOption();
// if (option != null && option.length() > 0) {
// buffer.append("PROP(" + option + ")");
// } else {
buffer.append("PROP(PROPERTIES)");
// }
} else if (converter instanceof LineSeparatorPatternConverter) {
//done
}
}
return buffer.toString();
}
public static Map getAppenderConfiguration(File file) {
try {
return getXMLFileAppenderConfiguration(file);
} catch (IOException | ParserConfigurationException | SAXException e) {
//ignore
}
try {
return getPropertiesFileAppenderConfiguration(file);
} catch (Exception e) {
//ignore
}
//don't return null
return new HashMap();
}
public static Map getPropertiesFileAppenderConfiguration(File propertyFile) throws IOException, ParserConfigurationException, SAXException {
Map<String, Map<String, String>> result = new HashMap<>();
String appenderPrefix = "log4j.appender";
Properties props = new Properties();
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(propertyFile);
props.load(inputStream);
Enumeration propertyNames = props.propertyNames();
Map<String, String> appenders = new HashMap<>();
while (propertyNames.hasMoreElements()) {
String propertyName = propertyNames.nextElement().toString();
if (propertyName.startsWith(appenderPrefix)) {
String value = propertyName.substring(appenderPrefix.length() + 1);
if (value.indexOf(".") == -1) {
//no sub-values - this entry is the appender name & class
appenders.put(value, props.getProperty(propertyName).trim());
}
}
}
for (Map.Entry<String, String> appenderEntry : appenders.entrySet()) {
String appenderName = appenderEntry.getKey();
String appenderClassName = appenderEntry.getValue();
if (appenderClassName.toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
String layout = props.getProperty(appenderPrefix + "." + appenderName + ".layout");
if (layout != null && layout.trim().equals("org.apache.log4j.PatternLayout")) {
String conversion = props.getProperty(appenderPrefix + "." + appenderName + ".layout.ConversionPattern");
String file = props.getProperty(appenderPrefix + "." + appenderName + ".File");
if (conversion != null && file != null) {
Map<String, String> entry = new HashMap<>();
entry.put("file", file.trim());
entry.put("conversion", conversion.trim());
result.put(appenderName, entry);
}
}
}
}
/*
example:
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${catalina.base}/logs/tomcat.log
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d - %p %t %c - %m%n
*/
}
catch (IOException ioe) {
}
finally {
if (inputStream != null) {
inputStream.close();
}
}
//don't return null
return result;
}
private static Map getXMLFileAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
Map<String, Map<String, String>> result = new HashMap<>();
try (InputStream stream = file.toURI().toURL().openStream()) {
InputSource src = new InputSource(stream);
src.setSystemId(file.toURI().toURL().toString());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
docBuilder.setErrorHandler(new SAXErrorHandler());
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");
if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
//all log4j fileappenders end in fileappender..if a custom fileappender also ends in fileappender and uses the same dom nodes to be loaded,
//try to parse the nodes as well
if (appenderClass.getNodeValue().toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
//subclass of FileAppender - add it
Map<String, String> 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().equalsIgnoreCase("file")) {
Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
if (fileValueNode != null) {
entry.put("file", fileValueNode.getNodeValue());
}
}
}
if (appenderChild.getNodeName().equalsIgnoreCase("layout") && appenderChild.hasAttributes()) {
NamedNodeMap layoutAttributes = appenderChild.getAttributes();
Node layoutNode = layoutAttributes.getNamedItem("class");
if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equalsIgnoreCase("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().equalsIgnoreCase("conversionpattern")) {
Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
if (conversionValue != null) {
entry.put("conversion", conversionValue.getNodeValue());
}
}
}
}
}
}
}
result.put(appenderName, entry);
}
}
}
}
MessageCenter.getInstance().getLogger().info("getXMLFileAppenderConfiguration for file: " + file + ", result: " + result);
return result;
}
}