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 logs = Collections.synchronizedList(new ArrayList<>()); private final List 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 levelStats = countByLevel(); Map moduleErrorStats = countModuleErrors(); List 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 countByLevel() { Map stats = new HashMap<>(); synchronized (logs) { for (Log log : logs) { stats.merge(log.getLevel(), 1, Integer::sum); } } return stats; } private Map countModuleErrors() { Map 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 getEarliestLogs(int count) { List 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 levelStats, Map moduleErrorStats, List 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; } } } }