227 lines
8.3 KiB
Java
227 lines
8.3 KiB
Java
package com.inmind.student.杨靖宇;
|
|
|
|
import java.io.*;
|
|
import java.net.Socket;
|
|
import java.util.*;
|
|
import java.net.*;
|
|
|
|
|
|
public class LogAnalyzer {
|
|
private static final String LOG_DIR = "D:\\io_test";
|
|
private static final String SERVER_HOST = "localhost";
|
|
private static final int SERVER_PORT = 8080;
|
|
|
|
private final List<Log> logs = Collections.synchronizedList(new ArrayList<>());
|
|
private final List<Thread> threads = new ArrayList<>();
|
|
|
|
public static void main(String[] args) {
|
|
LogAnalyzer analyzer = new LogAnalyzer();
|
|
try {
|
|
analyzer.analyze();
|
|
} catch (FileNotFoundException e) {
|
|
System.err.println("[错误] 日志目录不存在: " + e.getMessage());
|
|
} catch (Exception e) {
|
|
System.err.println("[错误] 分析过程中出现异常: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public void analyze() throws FileNotFoundException {
|
|
// 1. 检查并创建日志目录
|
|
ensureLogDirectoryExists();
|
|
|
|
// 2. 读取日志文件
|
|
readLogFiles();
|
|
|
|
// 3. 等待所有线程完成
|
|
waitForThreads();
|
|
|
|
if (logs.isEmpty()) {
|
|
System.out.println("[提示] 没有解析到任何有效日志");
|
|
return;
|
|
}
|
|
|
|
// 4. 统计日志数据
|
|
Map<String, Integer> levelStats = countByLevel();
|
|
Map<String, Integer> moduleErrorStats = countModuleErrors();
|
|
List<Log> earliestLogs = getEarliestLogs(3);
|
|
|
|
// 5. 上报统计结果
|
|
reportToServer(levelStats, moduleErrorStats, earliestLogs);
|
|
}
|
|
|
|
private void ensureLogDirectoryExists() throws FileNotFoundException {
|
|
File logDir = new File(LOG_DIR);
|
|
if (!logDir.exists()) {
|
|
System.out.println("[提示] 日志目录不存在,尝试创建...");
|
|
if (!logDir.mkdirs()) {
|
|
throw new FileNotFoundException("无法创建日志目录: " + LOG_DIR);
|
|
}
|
|
System.out.println("[成功] 已创建日志目录: " + LOG_DIR);
|
|
}
|
|
}
|
|
|
|
private void readLogFiles() throws FileNotFoundException {
|
|
File logDir = new File(LOG_DIR);
|
|
File[] logFiles = logDir.listFiles((dir, name) -> name.endsWith(".log"));
|
|
|
|
if (logFiles == null || logFiles.length == 0) {
|
|
System.out.println("[提示] 目录中没有找到.log文件");
|
|
return;
|
|
}
|
|
|
|
System.out.printf("[信息] 找到 %d 个日志文件\n", logFiles.length);
|
|
|
|
for (File file : logFiles) {
|
|
Thread thread = new Thread(() -> parseLogFile(file));
|
|
threads.add(thread);
|
|
thread.start();
|
|
}
|
|
}
|
|
|
|
private void waitForThreads() {
|
|
for (Thread thread : threads) {
|
|
try {
|
|
thread.join();
|
|
} catch (InterruptedException e) {
|
|
System.err.println("[警告] 线程等待被中断");
|
|
Thread.currentThread().interrupt();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void parseLogFile(File file) {
|
|
System.out.printf("[信息] 开始解析文件: %s\n", file.getName());
|
|
|
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
|
String line;
|
|
int lineNum = 0;
|
|
int successCount = 0;
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
lineNum++;
|
|
try {
|
|
Log log = parseLogLine(line);
|
|
logs.add(log);
|
|
successCount++;
|
|
} catch (NumberFormatException e) {
|
|
System.err.printf("[警告] %s 第 %d 行: 时间戳格式错误\n",
|
|
file.getName(), lineNum);
|
|
} catch (IllegalArgumentException e) {
|
|
System.err.printf("[警告] %s 第 %d 行: 日志格式错误\n",
|
|
file.getName(), lineNum);
|
|
}
|
|
}
|
|
|
|
System.out.printf("[成功] 文件 %s 解析完成: 总行数 %d, 成功 %d, 失败 %d\n",
|
|
file.getName(), lineNum, successCount, lineNum - successCount);
|
|
} catch (FileNotFoundException e) {
|
|
System.err.printf("[错误] 文件不存在: %s\n", file.getPath());
|
|
} catch (IOException e) {
|
|
System.err.printf("[错误] 读取文件 %s 失败: %s\n", file.getName(), e.getMessage());
|
|
}
|
|
}
|
|
|
|
private Log parseLogLine(String line) throws IllegalArgumentException, NumberFormatException {
|
|
String[] parts = line.split(",", 4);
|
|
if (parts.length != 4) {
|
|
throw new IllegalArgumentException("需要4个字段但找到" + parts.length);
|
|
}
|
|
|
|
long timestamp = Long.parseLong(parts[0].trim());
|
|
return new Log(timestamp, parts[1].trim(), parts[2].trim(), parts[3].trim());
|
|
}
|
|
|
|
private Map<String, Integer> countByLevel() {
|
|
Map<String, Integer> stats = new HashMap<>();
|
|
synchronized (logs) {
|
|
for (Log log : logs) {
|
|
stats.merge(log.getLevel(), 1, Integer::sum);
|
|
}
|
|
}
|
|
return stats;
|
|
}
|
|
|
|
private Map<String, Integer> countModuleErrors() {
|
|
Map<String, Integer> stats = new HashMap<>();
|
|
synchronized (logs) {
|
|
for (Log log : logs) {
|
|
if ("ERROR".equals(log.getLevel())) {
|
|
stats.merge(log.getModule(), 1, Integer::sum);
|
|
}
|
|
}
|
|
}
|
|
return stats;
|
|
}
|
|
|
|
private List<Log> getEarliestLogs(int count) {
|
|
List<Log> copy;
|
|
synchronized (logs) {
|
|
copy = new ArrayList<>(logs);
|
|
}
|
|
|
|
if (copy.isEmpty()) {
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
copy.sort(Comparator.comparingLong(Log::getTimestamp));
|
|
return new ArrayList<>(copy.subList(0, Math.min(count, copy.size())));
|
|
}
|
|
|
|
private void reportToServer(Map<String, Integer> levelStats,
|
|
Map<String, Integer> moduleErrorStats,
|
|
List<Log> earliestLogs) {
|
|
final int maxRetries = 3;
|
|
int attempt = 0;
|
|
|
|
while (attempt < maxRetries) {
|
|
attempt++;
|
|
try (Socket socket = new Socket()) {
|
|
// 设置连接和读取超时
|
|
socket.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT), 5000);
|
|
socket.setSoTimeout(10000);
|
|
|
|
try (ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
|
|
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
|
|
|
|
// 确保发送的是可序列化的ArrayList
|
|
oos.writeObject(new HashMap<>(levelStats));
|
|
oos.writeObject(new HashMap<>(moduleErrorStats));
|
|
oos.writeObject(new ArrayList<>(earliestLogs));
|
|
oos.flush();
|
|
|
|
String response = (String) ois.readObject();
|
|
System.out.println("[成功] 服务器响应: " + response);
|
|
return;
|
|
}
|
|
} catch (ConnectException e) {
|
|
System.err.printf("[错误] 连接失败(尝试 %d/%d): %s\n",
|
|
attempt, maxRetries, e.getMessage());
|
|
if (attempt >= maxRetries) {
|
|
System.err.println("[错误] 达到最大重试次数,放弃连接");
|
|
} else {
|
|
try {
|
|
Thread.sleep(1000 * attempt);
|
|
} catch (InterruptedException ie) {
|
|
Thread.currentThread().interrupt();
|
|
return;
|
|
}
|
|
}
|
|
} catch (SocketTimeoutException e) {
|
|
System.err.println("[错误] 连接或读取超时");
|
|
} catch (EOFException e) {
|
|
System.err.println("[错误] 连接意外中断");
|
|
} catch (UnknownHostException e) {
|
|
System.err.println("[错误] 未知主机: " + SERVER_HOST);
|
|
break;
|
|
} catch (IOException e) {
|
|
System.err.println("[错误] 通信错误: " + e.getMessage());
|
|
break;
|
|
} catch (ClassNotFoundException e) {
|
|
System.err.println("[错误] 协议错误: 收到未知响应类型");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |