
分析提供的 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 {
//初始化数组。
List list = 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条)