added support for 'custom level definitions' in LogFilePatternReceiver, which allows the user to map strings in the log file to Log4j levels
if there are extra spaces that would prevent a pattern from matching, strip them out
exclude empty lines (if appendNonMatches was false, would add an empty line to the log)
With these changes, redirection of Android logging via 'logcat -v time' will now render fine in Chainsaw, using:
<param name="logFormat" value="TIMESTAMP LEVEL/LOGGER(PROP(PID)):MESSAGE"/>
<param name="customLevelDefinitions" value="V=TRACE,D=DEBUG,I=INFO,W=WARN,E=ERROR,F=FATAL,S=OFF"/>
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/companions/receivers/trunk@941180 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index 1f54b5e..0b4f45b 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -31,6 +31,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.StringTokenizer;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
@@ -158,11 +159,10 @@
private static final String REGEXP_DEFAULT_WILDCARD = ".*?";
private static final String REGEXP_GREEDY_WILDCARD = ".*";
private static final String PATTERN_WILDCARD = "*";
- private static final String NOSPACE_GROUP = "(\\S*?)";
+ private static final String NOSPACE_GROUP = "(\\S*\\s*?)";
private static final String DEFAULT_GROUP = "(" + REGEXP_DEFAULT_WILDCARD + ")";
private static final String GREEDY_GROUP = "(" + REGEXP_GREEDY_WILDCARD + ")";
private static final String MULTIPLE_SPACES_REGEXP = "[ ]+";
-
private final String newLine = System.getProperty("line.separator");
private final String[] emptyException = new String[] { "" };
@@ -170,6 +170,7 @@
private SimpleDateFormat dateFormat;
private String timestampFormat = "yyyy-MM-d HH:mm:ss,SSS";
private String logFormat;
+ private String customLevelDefinitions;
private String fileURL;
private String host;
private String path;
@@ -197,6 +198,7 @@
private boolean useCurrentThread;
public static final int MISSING_FILE_RETRY_MILLIS = 10000;
private boolean appendNonMatches;
+ private final Map customLevelDefinitionMap = new HashMap();
public LogFilePatternReceiver() {
keywords.add(TIMESTAMP);
@@ -235,6 +237,20 @@
this.fileURL = fileURL;
}
+ /**
+ * If the log file contains non-log4j level strings, they can be mapped to log4j levels using the format (android example):
+ * V=TRACE,D=DEBUG,I=INFO,W=WARN,E=ERROR,F=FATAL,S=OFF
+ *
+ * @param customLevelDefinitions the level definition string
+ */
+ public void setCustomLevelDefinitions(String customLevelDefinitions) {
+ this.customLevelDefinitions = customLevelDefinitions;
+ }
+
+ public String getCustomLevelDefinitions() {
+ return customLevelDefinitions;
+ }
+
/**
* Accessor
* @return append non matches
@@ -479,6 +495,8 @@
Perl5Matcher eventMatcher = new Perl5Matcher();
String line;
while ((line = bufferedReader.readLine()) != null) {
+ //skip empty line entries
+ if (line.trim().equals("")) {continue;}
if (eventMatcher.matches(line, regexpPattern)) {
//build an event from the previous match (held in current map)
LoggingEvent event = buildEvent();
@@ -631,7 +649,8 @@
dateFormat = new SimpleDateFormat(timestampFormat);
timestampPatternText = convertTimestamp();
}
-
+ //if custom level definitions exist, parse them
+ updateCustomLevelDefinitionMap();
try {
if (filterExpression != null) {
expressionRule = ExpressionRule.getRule(filterExpression);
@@ -729,6 +748,18 @@
getLogger().debug("regexp is " + regexp);
}
+ private void updateCustomLevelDefinitionMap() {
+ if (customLevelDefinitions != null) {
+ StringTokenizer entryTokenizer = new StringTokenizer(customLevelDefinitions, ",");
+
+ customLevelDefinitionMap.clear();
+ while (entryTokenizer.hasMoreTokens()) {
+ StringTokenizer innerTokenizer = new StringTokenizer(entryTokenizer.nextToken(), "=");
+ customLevelDefinitionMap.put(innerTokenizer.nextToken(), Level.toLevel(innerTokenizer.nextToken()));
+ }
+ }
+ }
+
private boolean isInteger(String value) {
try {
Integer.parseInt(value);
@@ -847,11 +878,24 @@
}
level = (String) fieldMap.remove(LEVEL);
- Level levelImpl = (level == null ? Level.DEBUG : Level.toLevel(level.trim()));
- if (level != null && !level.equals(levelImpl.toString())) {
- getLogger().debug("found unexpected level: " + level + ", logger: " + logger.getName() + ", msg: " + message);
- //make sure the text that couldn't match a level is added to the message
- message = level + " " + message;
+ Level levelImpl;
+ if (level == null) {
+ levelImpl = Level.DEBUG;
+ } else {
+ //first try to resolve against custom level definition map, then fall back to regular levels
+ levelImpl = (Level) customLevelDefinitionMap.get(level);
+ if (levelImpl == null) {
+ levelImpl = Level.toLevel(level.trim());
+ if (!level.equals(levelImpl.toString())) {
+ //check custom level map
+ if (levelImpl == null) {
+ levelImpl = Level.DEBUG;
+ getLogger().debug("found unexpected level: " + level + ", logger: " + logger.getName() + ", msg: " + message);
+ //make sure the text that couldn't match a level is added to the message
+ message = level + " " + message;
+ }
+ }
+ }
}
threadName = (String) fieldMap.remove(THREAD);
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
index ba26f90..f99f289 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
@@ -42,6 +42,7 @@
"filterExpression", LogFilePatternReceiver.class),
new PropertyDescriptor("waitMillis", LogFilePatternReceiver.class),
new PropertyDescriptor("appendNonMatches", LogFilePatternReceiver.class),
+ new PropertyDescriptor("customLevelDefinitions", LogFilePatternReceiver.class),
new PropertyDescriptor("useCurrentThread", LogFilePatternReceiver.class),
};
} catch (Exception e) {