import java.io.*;
import java.nio.file.*;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
/**
* WebLogic Performance Analyzer
* Analyzes WebLogic server logs to compare performance before and after infrastructure upgrades.
*/
public class WebLogicPerformanceAnalyzer {
// Regular expressions for different timing patterns
private static final Pattern INIT_PATTERN = Pattern.compile("initialization completed in (\\d+) ms");
private static final Pattern TIME_TAKEN_PATTERN = Pattern.compile("\\*\\|\\*Time taken for\\*\\|\\*(.+?)\\*\\|\\*is\\*\\|\\*(\\d+)\\*\\|\\*ms");
private static final Pattern THREAD_INFO_PATTERN = Pattern.compile("ExecuteThread: '(\\d+)'");
// Filter out non-performance related patterns containing "ms"
private static final Pattern TOKEN_EXPIRY_PATTERN = Pattern.compile("token to expire");
private static final Pattern SYSTEM_DATETIME_PATTERN = Pattern.compile("system date time");
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: java WebLogicPerformanceAnalyzer <beforeLogsDir> <afterLogsDir>");
System.out.println("Example: java WebLogicPerformanceAnalyzer ./logs/before ./logs/after");
return;
}
String beforeDir = args[0];
String afterDir = args[1];
try {
// Process "before" and "after" logs
Map<String, List<Integer>> beforeOperationTimes = processLogsDirectory(beforeDir);
Map<String, List<Integer>> afterOperationTimes = processLogsDirectory(afterDir);
// Generate performance comparison report
generateReport(beforeOperationTimes, afterOperationTimes);
} catch (IOException e) {
System.err.println("Error processing log files: " + e.getMessage());
e.printStackTrace();
}
}
/**
* Process all log files in a directory
*/
private static Map<String, List<Integer>> processLogsDirectory(String directoryPath) throws IOException {
Map<String, List<Integer>> operationTimes = new HashMap<>();
File directory = new File(directoryPath);
File[] logFiles = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".txt") || name.toLowerCase().endsWith(".log"));
if (logFiles != null) {
for (File logFile : logFiles) {
processLogFile(logFile, operationTimes);
}
}
return operationTimes;
}
/**
* Process a single log file to extract timing information
*/
private static void processLogFile(File logFile, Map<String, List<Integer>> operationTimes) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(logFile))) {
String line;
while ((line = reader.readLine()) != null) {
// Skip lines with token expiry or system datetime
if (TOKEN_EXPIRY_PATTERN.matcher(line).find() || SYSTEM_DATETIME_PATTERN.matcher(line).find()) {
continue;
}
// Extract initialization times
Matcher initMatcher = INIT_PATTERN.matcher(line);
if (initMatcher.find()) {
int timeMs = Integer.parseInt(initMatcher.group(1));
addOperationTime(operationTimes, "initialization", timeMs);
continue;
}
// Extract "Time taken for" operation times
Matcher timeTakenMatcher = TIME_TAKEN_PATTERN.matcher(line);
if (timeTakenMatcher.find()) {
String operation = timeTakenMatcher.group(1);
int timeMs = Integer.parseInt(timeTakenMatcher.group(2));
addOperationTime(operationTimes, operation, timeMs);
}
}
}
}
/**
* Add operation time to the map
*/
private static void addOperationTime(Map<String, List<Integer>> operationTimes, String operation, int timeMs) {
operationTimes.computeIfAbsent(operation, k -> new ArrayList<>()).add(timeMs);
}
/**
* Generate a performance comparison report
*/
private static void generateReport(Map<String, List<Integer>> beforeTimes, Map<String, List<Integer>> afterTimes) {
System.out.println("WebLogic Performance Analysis Report");
System.out.println("=====================================");
System.out.println();
// Create a unified set of all operations from both before and after
Set<String> allOperations = new HashSet<>();
allOperations.addAll(beforeTimes.keySet());
allOperations.addAll(afterTimes.keySet());
// Sort operations by average time in "before" logs (descending)
List<String> sortedOperations = allOperations.stream()
.sorted((op1, op2) -> {
double avg1 = beforeTimes.containsKey(op1) ? calculateAverage(beforeTimes.get(op1)) : 0;
double avg2 = beforeTimes.containsKey(op2) ? calculateAverage(beforeTimes.get(op2)) : 0;
return Double.compare(avg2, avg1); // Descending order
})
.collect(Collectors.toList());
// Print table header
System.out.printf("%-40s | %-15s | %-15s | %-15s%n", "Operation", "Before Upgrade", "After Upgrade", "Improvement");
System.out.println(String.join("", Collections.nCopies(95, "-")));
DecimalFormat df = new DecimalFormat("#,##0.00");
// Print each operation's statistics
for (String operation : sortedOperations) {
double beforeAvg = beforeTimes.containsKey(operation) ? calculateAverage(beforeTimes.get(operation)) : 0;
double afterAvg = afterTimes.containsKey(operation) ? calculateAverage(afterTimes.get(operation)) : 0;
String beforeStr = beforeTimes.containsKey(operation) ? df.format(beforeAvg) + " ms" : "N/A";
String afterStr = afterTimes.containsKey(operation) ? df.format(afterAvg) + " ms" : "N/A";
String improvementStr = "N/A";
if (beforeTimes.containsKey(operation) && afterTimes.containsKey(operation) && beforeAvg > 0) {
double improvementPct = ((beforeAvg - afterAvg) / beforeAvg) * 100;
improvementStr = df.format(improvementPct) + "%";
}
System.out.printf("%-40s | %-15s | %-15s | %-15s%n",
operation.length() > 40 ? operation.substring(0, 37) + "..." : operation,
beforeStr, afterStr, improvementStr);
}
System.out.println();
System.out.println("Summary Statistics");
System.out.println("-----------------");
// Calculate overall average improvement
List<Double> improvementPercentages = new ArrayList<>();
for (String operation : allOperations) {
if (beforeTimes.containsKey(operation) && afterTimes.containsKey(operation)) {
double beforeAvg = calculateAverage(beforeTimes.get(operation));
double afterAvg = calculateAverage(afterTimes.get(operation));
if (beforeAvg > 0) {
double improvementPct = ((beforeAvg - afterAvg) / beforeAvg) * 100;
improvementPercentages.add(improvementPct);
}
}
}
if (!improvementPercentages.isEmpty()) {
double avgImprovement = calculateAverage(improvementPercentages);
System.out.println("Average performance improvement across all operations: " + df.format(avgImprovement) + "%");
}
// Top 5 most improved operations
if (!improvementPercentages.isEmpty()) {
System.out.println();
System.out.println("Top 5 Most Improved Operations");
System.out.println("-----------------------------");
allOperations.stream()
.filter(op -> beforeTimes.containsKey(op) && afterTimes.containsKey(op))
.sorted((op1, op2) -> {
double beforeAvg1 = calculateAverage(beforeTimes.get(op1));
double afterAvg1 = calculateAverage(afterTimes.get(op1));
double imp1 = beforeAvg1 > 0 ? ((beforeAvg1 - afterAvg1) / beforeAvg1) * 100 : 0;
double beforeAvg2 = calculateAverage(beforeTimes.get(op2));
double afterAvg2 = calculateAverage(afterTimes.get(op2));
double imp2 = beforeAvg2 > 0 ? ((beforeAvg2 - afterAvg2) / beforeAvg2) * 100 : 0;
return Double.compare(imp2, imp1); // Descending order
})
.limit(5)
.forEach(op -> {
double beforeAvg = calculateAverage(beforeTimes.get(op));
double afterAvg = calculateAverage(afterTimes.get(op));
double improvementPct = ((beforeAvg - afterAvg) / beforeAvg) * 100;
System.out.printf("%-40s: %s%% improvement (%s ms → %s ms)%n",
op.length() > 40 ? op.substring(0, 37) + "..." : op,
df.format(improvementPct),
df.format(beforeAvg),
df.format(afterAvg));
});
}
}
/**
* Calculate average of a list of integers
*/
private static double calculateAverage(List<Integer> values) {
if (values == null || values.isEmpty()) {
return 0;
}
return values.stream().mapToDouble(Integer::doubleValue).average().orElse(0);
}
/**
* Calculate average of a list of doubles
*/
private static double calculateAverage(List<Double> values) {
if (values == null || values.isEmpty()) {
return 0;
}
return values.stream().mapToDouble(Double::doubleValue).average().orElse(0);
}
}