分析提供的 redis.log 日志文件,要求:
统计数据库的存盘次数(以「DB saved on disk」的出现为标识);
统计出最小存盘时间和最大存盘时间(以「Background saving started by pid xxxx」为开始时间,以「DB saved on disk」为结束时间,这两个时间之间的长度间隔即为存盘时间),如果有多个最小存盘时间和最大存盘时间,那么就取开始时间最早的那个;
找出存盘时是否出现了重复的进程号(就是开始时间 pid 后的数值);
以「*」为分界,统计「*」之后出现的单词数量,以及出现频率最高的单词,并从大到小排序(如果有多个单词并列最大,那么全列出来);
要求代码中必须使用 Lambda 表达式;
答:
实现代码:
package com.xxm.advanced_camp.greatmission4_loganalysis; import java.io.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.Map; public class LogAnalysis_List { public static void readFile(String filePath) throws Exception { //初始化数组。 Listlist = new ArrayList<>(); //定义计数器,用于记录存盘次数 int saveCounts = 0; File file = new File(filePath); FileInputStream fileInputStream = new FileInputStream(file); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); while (bufferedReader.read() != -1) { list.add(bufferedReader.readLine()); } //文件行数 long fileLen = list.size(); List savedCountList = list.stream() .filter(s -> s.contains("DB saved on disk")) .collect(Collectors.toList()); for (String s : savedCountList) { saveCounts++; } //开始存储时间的数组。 List saveStartTimeList = timeInList(list, "Background saving started by pid"); //调用 toDate 方法,把字符串列表转化为 Date 列表 List saveStartTimeDateList = toDate(saveStartTimeList); //完成存储时间的数组。 List saveEndTimeList = timeInList(list, "DB saved on disk"); //调用 toDate 方法,把字符串列表转化为时间列表 List saveEndTimeDateList = toDate(saveEndTimeList); //存储消耗时间的数组 List saveSpentTimeList = new ArrayList<>(); for (int i = 0; i < saveStartTimeList.size(); i++) { saveSpentTimeList.add(saveEndTimeDateList.get(i).getTime() - saveStartTimeDateList.get(i).getTime()); } long maxSaveTime = saveSpentTimeList.get(0); long minSaveTime = saveSpentTimeList.get(0); for (int i = 0; i < saveSpentTimeList.size(); i++) { if (saveSpentTimeList.get(i) < minSaveTime) { minSaveTime = saveSpentTimeList.get(i); } else if (saveSpentTimeList.get(i) > maxSaveTime) { maxSaveTime = saveSpentTimeList.get(i); } } //统计 * 号后出现的单词 HashMap wordMap = new HashMap<>(100); for (String str : list) { String[] arr = str.split(" "); for (int i = 4; i < arr.length; i++) { //先判断它是不是数字 if (!isNumeric(arr[i])) { //如果集合中没有该单词,则添加,并且次数记为 1。 if (!wordMap.containsKey(arr[i])) { wordMap.put(arr[i], 1); } //如果集合中有该单词,则将其次数 +1。 else if (wordMap.containsKey(arr[i])) { Integer count = wordMap.get(arr[i]); wordMap.replace(arr[i], count + 1); } } } } //统计 pid HashMap pidMap = new HashMap<>(100); List pidList = list.stream() .filter(s -> s.contains("pid")) .collect(Collectors.toList()); for (String str : pidList) { String[] arr = str.split(" "); //因为 pid 在日志中是第 10 个,因此索引为 9 //如果集合中没有该 pid,则添加,并且次数记为 1。 if (!pidMap.containsKey(arr[9])) { pidMap.put(arr[9], 1); } //如果集合中有该 pid,则将其次数 +1。 else if (pidMap.containsKey(arr[9])) { Integer count = pidMap.get(arr[9]); pidMap.replace(arr[9], count + 1); } } //对 wordMap 中的数据排序 List > sortedWordMap = new ArrayList >(wordMap.entrySet()); //通过比较器降序排序 Collections.sort(sortedWordMap, ((o1, o2) -> o2.getValue(). compareTo(o1.getValue()))); //筛选 pidMap 中 value 大于 1 的数据 Collection values = pidMap.values(); while (values.contains(1)) { values.remove(1); } List > repeatedPidMap = new ArrayList >(pidMap.entrySet()); //此处为代码末尾: //输出文件的总行数 System.out.println("文件总行数为:" + fileLen + "行"); // 输出存储数据的次数 System.out.println("存储数据的次数为:" + saveCounts + "次"); //输出最大、最小存储时间 System.out.println("最大存储时间为:" + maxSaveTime + "毫秒"); System.out.println("最小存储时间为:" + minSaveTime + "毫秒"); //输出 * 后出现的单词,及其次数 System.out.println("单词出现的次数为(降序排列):"); for ( Map.Entry entry : sortedWordMap) { System.out.println(entry.getKey() + ":" + entry.getValue() + " 次"); } //输出重复出现的pid System.out.println("重复出现的pid有:"); for ( Map.Entry entry : repeatedPidMap) { System.out.println(entry.getKey() + ":" + entry.getValue() + " 次"); } } // toDate方法: public static List toDate(List stringList) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); List dateList = new ArrayList<>(); for (String s : stringList) { try { Date d = sdf.parse(s); dateList.add(d); } catch (ParseException e) { e.printStackTrace(); } } return dateList; } //获取时间数组的方法,传入参数为list列表和关键字 public static List timeInList(List list, String keyword) { List TimeList = new ArrayList<>(); list.stream() .filter(s -> s.contains(keyword)) .forEach(s -> { s = (s.split(" ")[1] + " " + s.split(" ")[2]); TimeList.add(s); }); return TimeList; } //判断字符串是否为数字的方法 public static boolean isNumeric(String str) { return str.chars().allMatch(Character::isDigit); } public static void main(String[] args) { try { readFile("C:\Users\yyq\Desktop\redis.log"); } catch (Exception e) { e.printStackTrace(); } } }
输出结果:
文件总行数为:101143行 存储数据的次数为:20229次 最大存储时间为:5200毫秒 最小存储时间为:4毫秒 单词出现的次数为(降序排列): Background:40457 次 saving:40457 次 by:40457 次 saved:20229 次 pid:20229 次 seconds:20229 次 in:20229 次 disk:20229 次 changes:20229 次 on:20229 次 started:20229 次 DB:20229 次 used:20228 次 MB:20228 次 success:20228 次 memory:20228 次 RDB::20228 次 copy-on-write:20228 次 of:20228 次 terminated:20228 次 with:20228 次 重复出现的pid有: 4970:2 次 2304:2 次 3631:2 次 3633:2 次 2309:2 次 3635:2 次 ...后略
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)