Java基础-E:日志分析
分析提供的 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;
/**
* @author xxm
* @date 2021年11月9日21:45:29
*/
public class LogAnalysis_List {
public static void readFile(String filePath) throws Exception {
//初始化数组。
List<String> 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<String> savedCountList = list.stream()
.filter(s -> s.contains("DB saved on disk"))
.collect(Collectors.toList());
for (String s : savedCountList) {
saveCounts++;
}
//开始存储时间的数组。
List<String> saveStartTimeList = timeInList(list, "Background saving started by pid");
//调用 toDate 方法,把字符串列表转化为 Date 列表
List<Date> saveStartTimeDateList = toDate(saveStartTimeList);
//完成存储时间的数组。
List<String> saveEndTimeList = timeInList(list, "DB saved on disk");
//调用 toDate 方法,把字符串列表转化为时间列表
List<Date> saveEndTimeDateList = toDate(saveEndTimeList);
//存储消耗时间的数组
List<Long> 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<String, Integer> 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<String, Integer> pidMap = new HashMap<>(100);
List<String> 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<Map.Entry<String, Integer>> sortedWordMap = new ArrayList<Map.Entry<String, Integer>>(wordMap.entrySet());
//通过比较器降序排序
Collections.sort(sortedWordMap, ((o1, o2) -> o2.getValue().
compareTo(o1.getValue())));
//筛选 pidMap 中 value 大于 1 的数据
Collection<Integer> values = pidMap.values();
while (values.contains(1)) {
values.remove(1);
}
List<Map.Entry<String, Integer>> repeatedPidMap = new ArrayList<Map.Entry<String, Integer>>(pidMap.entrySet());
//此处为代码末尾:
//输出文件的总行数
System.out.println("文件总行数为:" + fileLen + "行");
// 输出存储数据的次数
System.out.println("存储数据的次数为:" + saveCounts + "次");
//输出最大、最小存储时间
System.out.println("最大存储时间为:" + maxSaveTime + "毫秒");
System.out.println("最小存储时间为:" + minSaveTime + "毫秒");
//输出 * 后出现的单词,及其次数
System.out.println("单词出现的次数为(降序排列):");
for (
Map.Entry<String, Integer> entry : sortedWordMap) {
System.out.println(entry.getKey() + ":" + entry.getValue() + " 次");
}
//输出重复出现的pid
System.out.println("重复出现的pid有:");
for (
Map.Entry<String, Integer> entry : repeatedPidMap) {
System.out.println(entry.getKey() + ":" + entry.getValue() + " 次");
}
}
// toDate方法:
public static List<Date> toDate(List<String> stringList) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
List<Date> 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<String> timeInList(List<String> list, String keyword) {
List<String> 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 次
...后略
这篇博客详细介绍了如何利用Java进行日志分析,特别是针对redis.log文件。主要内容包括统计数据库的存盘次数,确定最小和最大存盘时间,检查存盘过程中的进程号重复情况,以及分析以'*'分隔后的单词数量和最高频单词。文中强调了在代码实现中使用Lambda表达式的重要性。

1344

被折叠的 条评论
为什么被折叠?



