Skip to content

Commit

Permalink
Make non-regex filters faster
Browse files Browse the repository at this point in the history
  • Loading branch information
tibagni committed Oct 10, 2023
1 parent 3afdd17 commit f4fc745
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 49 deletions.
109 changes: 60 additions & 49 deletions src/main/java/com/tibagni/logviewer/filter/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ public class Filter {
private String name;
private Color color;
private LogLevel verbosity = LogLevel.VERBOSE;

private Pattern pattern;
private int flags = Pattern.CASE_INSENSITIVE;

private ContextInfo temporaryInfo;

private boolean isSimpleFilter;
public boolean wasLoadedFromLegacyFile = false;

private Filter() { }
Expand All @@ -34,6 +34,7 @@ public Filter(Filter from) throws FilterException {
applied = from.isApplied();
pattern = getPattern(from.pattern.pattern());
verbosity = from.verbosity;
isSimpleFilter = from.isSimpleFilter;
if (temporaryInfo != null) {
temporaryInfo = new ContextInfo(from.temporaryInfo);
}
Expand Down Expand Up @@ -69,6 +70,38 @@ public void updateFilter(String name, String pattern, Color color, LogLevel verb
this.color = color;
this.pattern = getPattern(pattern);
this.verbosity = verbosity;
this.isSimpleFilter = !StringUtils.isPotentialRegex(pattern);
}

public static Filter createFromString(String filterString) throws FilterException {
// See format in 'serializeFilter'
try {
String[] params = filterString.split(",");
if (params.length < 4) {
throw new IllegalArgumentException();
}

String[] rgb = params[3].split(":");
if (rgb.length != 3) {
throw new IllegalArgumentException("Wrong color format");
}

boolean isLegacy = params.length == 4;

String name = params[0];
String pattern = StringUtils.decodeBase64(params[1]);
Color color = new Color(Integer.parseInt(rgb[0]), Integer.parseInt(rgb[1]), Integer.parseInt(rgb[2]));
LogLevel verbosity = isLegacy ? LogLevel.VERBOSE : LogLevel.valueOf(params[4]);
int flags = Integer.parseInt(params[2]);
boolean isCaseSensitive = (flags & Pattern.CASE_INSENSITIVE) == 0;

Filter filter = new Filter();
filter.updateFilter(name, pattern, color, verbosity, isCaseSensitive);
filter.wasLoadedFromLegacyFile = isLegacy;
return filter;
} catch (Exception e) {
throw new FilterException("Wrong filter format: " + filterString, e);
}
}

public boolean isApplied() {
Expand Down Expand Up @@ -120,12 +153,23 @@ public boolean isCaseSensitive() {
*/
public boolean appliesTo(LogEntry entry) {
String inputLine = entry.getLogText();
boolean foundPattern = pattern.matcher(inputLine).find();
boolean foundPattern = isSimpleFilter ? simpleMatch(inputLine) : regexMatch(inputLine);
boolean isVerbosityAllowed = verbosity.ordinal() <= entry.logLevel.ordinal();

return foundPattern && isVerbosityAllowed;
}

private boolean simpleMatch(String inputLine) {
if (isCaseSensitive()) {
return inputLine.contains(getPatternString());
}
return inputLine.toLowerCase().contains(getPatternString().toLowerCase());
}

private boolean regexMatch(String inputLine) {
return pattern.matcher(inputLine).find();
}

private Pattern getPattern(String pattern) throws FilterException {
try {
return Pattern.compile(pattern, flags);
Expand All @@ -151,37 +195,21 @@ public String serializeFilter() {
verbosity);
}

public static Filter createFromString(String filterString) throws FilterException {
// See format in 'serializeFilter'
try {
String[] params = filterString.split(",");
if (params.length < 4) {
throw new IllegalArgumentException();
}

Filter filter = new Filter();
filter.name = params[0];
filter.flags = Integer.parseInt(params[2]);
filter.pattern = filter.getPattern(StringUtils.decodeBase64(params[1]));

String[] rgb = params[3].split(":");
if (rgb.length != 3) {
throw new IllegalArgumentException("Wrong color format");
}

filter.color = new Color(Integer.parseInt(rgb[0]), Integer.parseInt(rgb[1]), Integer.parseInt(rgb[2]));

// Check if the filter has information about verbosity level
if (params.length > 4) {
filter.verbosity = LogLevel.valueOf(params[4]);
} else {
filter.wasLoadedFromLegacyFile = true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Filter filter = (Filter) o;
return flags == filter.flags &&
Objects.equals(name, filter.name) &&
Objects.equals(color, filter.color) &&
Objects.equals(getPatternString(), filter.getPatternString()) &&
Objects.equals(temporaryInfo, filter.temporaryInfo);
}

return filter;
} catch (Exception e) {
throw new FilterException("Wrong filter format: " + filterString, e);
}
@Override
public int hashCode() {
return Objects.hash(name, color, pattern, flags, temporaryInfo);
}

public static class ContextInfo {
Expand Down Expand Up @@ -238,21 +266,4 @@ public int hashCode() {
return Objects.hash(linesFound, allowedStreams);
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Filter filter = (Filter) o;
return flags == filter.flags &&
Objects.equals(name, filter.name) &&
Objects.equals(color, filter.color) &&
Objects.equals(getPatternString(), filter.getPatternString()) &&
Objects.equals(temporaryInfo, filter.temporaryInfo);
}

@Override
public int hashCode() {
return Objects.hash(name, color, pattern, flags, temporaryInfo);
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/tibagni/logviewer/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,15 @@ private static String escape(String text) {
public static String wrapHtml(String text) {
return "<html>" + text + "</html>";
}

public static boolean isPotentialRegex(String input) {
final String regexSpecialCharacters = ".*+?|()[]{}\\^$";
for (char c : input.toCharArray()) {
if (regexSpecialCharacters.contains(String.valueOf(c))) {
return true;
}
}

return false;
}
}
23 changes: 23 additions & 0 deletions src/test/java/com/tibagni/logviewer/util/StringUtilsTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,27 @@ class StringUtilsTests {
fun testHtmlEscape() {
assertEquals("&lt;&gt;&amp;&quot;", StringUtils.htmlEscape("<>&\""))
}

@Test
fun testPotentialRegexForValidRegex() {
assertTrue(StringUtils.isPotentialRegex(".*"))
assertTrue(StringUtils.isPotentialRegex("."))
assertTrue(StringUtils.isPotentialRegex("\\d{3}-\\d{2}-\\d{4}"))
assertTrue(StringUtils.isPotentialRegex("[A-Za-z]+"))
assertTrue(StringUtils.isPotentialRegex("\\d{1,3}"))
assertTrue(StringUtils.isPotentialRegex("(red|blue)"))
assertTrue(StringUtils.isPotentialRegex("a{5}"))
assertTrue(StringUtils.isPotentialRegex("a{3,5}"))
assertTrue(StringUtils.isPotentialRegex("^[A-Za-z]+$"))
assertTrue(StringUtils.isPotentialRegex("[0-9]{2,3}|[A-Za-z]{3,4}"))
assertTrue(StringUtils.isPotentialRegex("(\\d{3}-\\d{2}-\\d{4})|(\\d{4}-\\d{2}-\\d{2})"))
assertTrue(StringUtils.isPotentialRegex("word.word"))
}

@Test
fun testPotentialRegexForNonRegex() {
assertFalse(StringUtils.isPotentialRegex("Not a regex"))
assertFalse(StringUtils.isPotentialRegex("This is a normal string"))
assertFalse(StringUtils.isPotentialRegex("12345"))
}
}

0 comments on commit f4fc745

Please sign in to comment.