Skip to content

Commit

Permalink
Merge pull request #27 from jpage4500/feature/10-31
Browse files Browse the repository at this point in the history
Lots of changes to device logging (creating filters, searching)
  • Loading branch information
jpage4500 authored Nov 7, 2024
2 parents 5c85bac + 7c601e5 commit 6839239
Show file tree
Hide file tree
Showing 30 changed files with 1,038 additions and 453 deletions.
Binary file modified resources/screenshot-main.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 0 additions & 11 deletions src/main/java/com/jpage4500/devicemanager/data/FilterItem.java

This file was deleted.

18 changes: 18 additions & 0 deletions src/main/java/com/jpage4500/devicemanager/data/LogEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,22 @@ public LogEntry(String line, SimpleDateFormat dateFormat, int year) {
message = message.substring(tagPos + 1).trim();
}
}

@Override
public String toString() {
// NOTE: toString() is called when pressing CMD+C on JTable
return date +
", " +
app +
", " +
tid +
", " +
pid +
", " +
level +
", " +
tag +
", " +
message;
}
}
172 changes: 25 additions & 147 deletions src/main/java/com/jpage4500/devicemanager/data/LogFilter.java
Original file line number Diff line number Diff line change
@@ -1,127 +1,38 @@
package com.jpage4500.devicemanager.data;

import com.jpage4500.devicemanager.table.LogsTableModel;
import com.jpage4500.devicemanager.utils.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
* represents a named filter - which can contain multiple filter expressions
*/
public class LogFilter {
private static final Logger log = LoggerFactory.getLogger(LogFilter.class);
List<FilterExpression> filterList;

public enum Expression {
EQUALS("is"),
CONTAINS("contains"),
STARTS_WITH("starts with"),
ENDS_WITH("ends with"),
;
String desc;
public String name;
public boolean isSystemFilter; // true for built-in filters that can't be edited/deleted
public List<LogFilterEntry> filterList;

Expression(String desc) {
this.desc = desc;
}

@Override
public String toString() {
return desc;
}
public LogFilter() {
}

public static class FilterExpression {
public LogsTableModel.Columns column;
public boolean isNotExpression;
public Expression expression = Expression.EQUALS;
public String value;

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (column == null) sb.append("*");
else sb.append(column.name().toLowerCase());
sb.append(":");
if (TextUtils.equalsIgnoreCaseAny(value, "*", "")) {
sb.append("*");
} else {
if (isNotExpression) sb.append("!");
switch (expression) {
case STARTS_WITH:
sb.append(value);
sb.append("*");
break;
case ENDS_WITH:
sb.append("*");
sb.append(value);
break;
case CONTAINS:
sb.append("*");
sb.append(value);
sb.append("*");
break;
default:
sb.append(value);
break;
}
}

return sb.toString();
}

public boolean isMatch(LogEntry logEntry) {
boolean isMatch;
if (column != null) {
String logValue = null;
switch (column) {
case DATE -> logValue = logEntry.date;
case APP -> logValue = logEntry.app;
case TID -> logValue = logEntry.tid;
case PID -> logValue = logEntry.pid;
case LEVEL -> {
logValue = logEntry.level;
//log.trace("isMatch: {}, val:{}, expr:{}", logValue, value, expression);
if (value != null && expression == Expression.STARTS_WITH) {
switch (value) {
case "D":
return TextUtils.equalsIgnoreCaseAny(logValue, "D", "I", "W", "E");
case "I":
return TextUtils.equalsIgnoreCaseAny(logValue, "I", "W", "E");
case "W":
return TextUtils.equalsIgnoreCaseAny(logValue, "W", "E");
}
}
}
case TAG -> logValue = logEntry.tag;
case MSG -> logValue = logEntry.message;
}
isMatch = evaluateExpression(expression, logValue);
} else {
// match text from one of: message, app, tag
isMatch = evaluateExpression(expression, logEntry.message) ||
evaluateExpression(expression, logEntry.app) ||
evaluateExpression(expression, logEntry.tag);
}
return isNotExpression != isMatch;
}

private boolean evaluateExpression(Expression expression, String searchField) {
boolean isMatch = false;
if (expression == null) return false;
switch (expression) {
case EQUALS -> isMatch = TextUtils.equalsIgnoreCase(searchField, value);
case CONTAINS -> isMatch = TextUtils.containsAny(searchField, true, value);
case STARTS_WITH -> isMatch = TextUtils.startsWithAny(searchField, true, value);
case ENDS_WITH -> isMatch = TextUtils.endsWithAny(searchField, true, value);
}
return isMatch;
}
public LogFilter(LogFilter copy) {
this.name = "Copy of " + copy.name;
this.isSystemFilter = copy.isSystemFilter;
this.filterList = new ArrayList<>();
copy.filterList.forEach(logEntry -> {
LogFilterEntry copyEntry = LogFilterEntry.parse(logEntry.toString());
this.filterList.add(copyEntry);
});
}

public boolean isMatch(LogEntry logEntry) {
if (filterList == null) return false;
// iterate until 1 filter is 'false'
for (FilterExpression filter : filterList) {
for (LogFilterEntry filter : filterList) {
if (!filter.isMatch(logEntry)) return false;
}
// all filters matched - return true
Expand All @@ -131,59 +42,26 @@ public boolean isMatch(LogEntry logEntry) {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (FilterExpression expression : filterList) {
if (!sb.isEmpty()) sb.append(" && ");
sb.append(expression);
if (filterList != null) {
for (LogFilterEntry expression : filterList) {
if (!sb.isEmpty()) sb.append(" && ");
sb.append(expression);
}
}
return sb.toString();
return name + " -> " + sb;
}

public static LogFilter parse(String filterText) {
if (filterText == null) return null;
LogFilter filter = new LogFilter();
if (filterText == null) return filter;
filter.filterList = new ArrayList<>();
// TODO: support more than just "&&" (ie: "||")
String[] filterArr = filterText.split(" && ");
for (String entry : filterArr) {
String[] entryArr = entry.split(":", 2);
String key = entryArr[0].trim();
String value = entryArr[1].trim();
LogFilter.FilterExpression expr = new LogFilter.FilterExpression();
if (TextUtils.notEmpty(key)) {
String colName = key.toUpperCase();
try {
expr.column = LogsTableModel.Columns.valueOf(colName);
} catch (IllegalArgumentException e) {
}
}
if (TextUtils.equalsIgnoreCaseAny(value, "*", "")) {
LogFilterEntry expr = LogFilterEntry.parse(entry);
if (expr != null) {
filter.filterList.add(expr);
continue;
}
char firstChar = value.charAt(0);
if (firstChar == '!') {
expr.isNotExpression = true;
firstChar = value.charAt(1);
}
if (firstChar == '*') {
expr.expression = Expression.ENDS_WITH;
}
char lastChar = value.charAt(value.length() - 1);
if (lastChar == '*' || (expr.column == LogsTableModel.Columns.LEVEL && lastChar == '+')) {
if (expr.expression == Expression.ENDS_WITH) expr.expression = Expression.CONTAINS;
else expr.expression = Expression.STARTS_WITH;
}
int stPos = 0;
if (expr.isNotExpression) stPos++;
if (expr.expression == Expression.ENDS_WITH || expr.expression == Expression.CONTAINS) stPos++;

int endPos = value.length();
if (expr.expression == Expression.STARTS_WITH || expr.expression == Expression.CONTAINS) endPos--;

expr.value = value.substring(stPos, endPos);

//log.trace("parse: expr:{}", GsonHelper.toJson(expr));
filter.filterList.add(expr);
}
return filter;
}
Expand Down
Loading

0 comments on commit 6839239

Please sign in to comment.