import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
public class SQLLogAnalyzer {
// Updated pattern to capture the full query, including the "select" keyword
private static final Pattern LOG_PATTERN = Pattern.compile(".*?(\\[(ACTIVE|STUCK)\\])?.*?ExecuteThread:\\s+'(\\d+)'.*?((?:preparing: )?)(select.*)");
private final Map<String, QueryStats> queryDistribution;
public SQLLogAnalyzer() {
this.queryDistribution = new HashMap<>();
}
private static String repeatString(String str, int count) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++) {
sb.append(str);
}
return sb.toString();
}
public static class QueryStats {
private final String normalizedQuery;
private int occurrences;
private final Map<String, ThreadState> threadStates;
private final Set<Integer> lineNumbers;
public QueryStats(String query) {
this.normalizedQuery = normalizeQuery(query);
this.occurrences = 0;
this.threadStates = new HashMap<>();
this.lineNumbers = new HashSet<>();
}
private static String normalizeQuery(String query) {
return query.trim(); // Keep original case and spacing
}
public void addOccurrence(String threadId, String state, int lineNumber) {
occurrences++;
state = (state == null) ? "UNKNOWN" : state;
threadStates.computeIfAbsent(threadId, id -> new ThreadState())
.addState(state);
lineNumbers.add(lineNumber);
}
@Override
public String toString() {
return String.format(
"Query: %s%n" +
"Total Occurrences: %d%n" +
"Thread State Analysis:%n%s%n" +
"Line Numbers: %s%n",
normalizedQuery,
occurrences,
getThreadAnalysis(),
lineNumbers.stream()
.sorted()
.map(String::valueOf)
.collect(Collectors.joining(", "))
);
}
private String getThreadAnalysis() {
Map<String, Integer> stateCount = new HashMap<>();
Map<String, Set<String>> stateThreads = new HashMap<>();
Arrays.asList("ACTIVE", "STUCK", "UNKNOWN").forEach(state -> {
stateCount.put(state, 0);
stateThreads.put(state, new HashSet<>());
});
threadStates.forEach((threadId, state) -> {
state.getStateCounts().forEach((stateName, count) -> {
stateCount.merge(stateName, count, Integer::sum);
stateThreads.get(stateName).add(threadId);
});
});
StringBuilder analysis = new StringBuilder();
analysis.append(" Thread Distribution:\n");
Arrays.asList("ACTIVE", "STUCK", "UNKNOWN").forEach(state -> {
if (stateCount.get(state) > 0) {
analysis.append(String.format(" %s Threads: %d occurrences across %d threads%n",
state, stateCount.get(state), stateThreads.get(state).size()));
analysis.append(" Thread IDs: ").append(
stateThreads.get(state).stream()
.sorted(Comparator.comparingInt(Integer::parseInt))
.collect(Collectors.joining(", ")))
.append("\n");
}
});
return analysis.toString();
}
}
static class ThreadState {
private final Map<String, Integer> stateCounts;
public ThreadState() {
this.stateCounts = new HashMap<>();
}
public void addState(String state) {
stateCounts.merge(state, 1, Integer::sum);
}
public Map<String, Integer> getStateCounts() {
return stateCounts;
}
}
public void analyzeLogs(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException("File not found: " + filePath);
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
int lineNumber = 0;
System.out.println("Analyzing file: " + file.getAbsolutePath());
while ((line = reader.readLine()) != null) {
lineNumber++;
processLine(line, lineNumber);
}
}
}
private void processLine(String line, int lineNumber) {
Matcher matcher = LOG_PATTERN.matcher(line);
if (matcher.find()) {
String state = matcher.group(2); // This might be null
String threadId = matcher.group(3);
String query = matcher.group(5).trim();
queryDistribution
.computeIfAbsent(query, QueryStats::new)
.addOccurrence(threadId, state, lineNumber);
}
}
public void printAnalysis() {
System.out.println("\n=== SQL Query Analysis ===\n");
if (queryDistribution.isEmpty()) {
System.out.println("No SQL queries found in the log file.");
return;
}
queryDistribution.values().stream()
.sorted((a, b) -> Integer.compare(b.occurrences, a.occurrences))
.forEach(stats -> {
System.out.println(stats);
System.out.println(repeatString("-", 80) + "\n");
});
printSummaryStats();
}
private void printSummaryStats() {
System.out.println("=== Summary Statistics ===");
System.out.println("Total unique queries: " + queryDistribution.size());
Map<String, Integer> totalStateDistribution = new HashMap<>();
Map<String, Set<String>> totalThreadsByState = new HashMap<>();
queryDistribution.values().forEach(stats ->
stats.threadStates.forEach((threadId, state) ->
state.getStateCounts().forEach((stateName, count) -> {
totalStateDistribution.merge(stateName, count, Integer::sum);
totalThreadsByState.computeIfAbsent(stateName, k -> new HashSet<>()).add(threadId);
})));
System.out.println("\nOverall Thread State Distribution:");
totalStateDistribution.forEach((state, count) ->
System.out.printf("%s: %d occurrences across %d unique threads%n",
state, count, totalThreadsByState.get(state).size()));
}
public static void main(String[] args) {
SQLLogAnalyzer analyzer = new SQLLogAnalyzer();
Scanner scanner = new Scanner(System.in);
String filePath;
if (args.length == 1) {
filePath = args[0];
} else {
System.out.println("Please enter the path to your log file:");
System.out.println("(Example: C:/logs/weblogic.log or ./logs/weblogic.log)");
filePath = scanner.nextLine().trim();
}
try {
analyzer.analyzeLogs(filePath);
analyzer.printAnalysis();
} catch (FileNotFoundException e) {
System.err.println("Error: " + e.getMessage());
System.err.println("Please check if the file path is correct and try again.");
} catch (IOException e) {
System.err.println("Error processing log file: " + e.getMessage());
e.printStackTrace();
} finally {
scanner.close();
}
}
}
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)