题目要求
程序运行日志是重要的运维手段,需要尽量记录下有效信息、避免无效日志,而“海量日志”就是一种比较典型的日志使用问题大量打印相同或相似的内容,将有效日志淹没,还可能降低系统运行效率。因此需要“海量日志”抑制机制,避免系统运行时产生“海量日志”问题
“海量日志”定义10ms内 (<10ms)打印2条相同日志 (包含第2条均需要波抑制)或100ms内(<100ms)打印10条相似日志(去除数字后完全相同的两即: 仅保留第一条;条日志认为是“相似”,包含第10条均需要被抑制),即:仅保留前9条日志抑制的理解:被抑制的日志,不记录到日志文件中。
输入样例
- 要求:
- 输入本用例的日志条数(最大不超过1000条)
时间戳:日志打印内容
约束: - 时间戳单位是ms,用32位无符号十进制整数表示
- 用例保证后一条日志时间戳不小于前一条;
- 一条日志打印只占一行,一条日志内容不超过1024 Bytes;
- 用例保证1s内(<1s),最多100条日志
- 数字均为正整数。
输出
时间戳:日志打印内容
输出需要除去被抑制的日志
- 输入本用例的日志条数(最大不超过1000条)
- 样例:
- 输入:
4
123:This is a log
123:This is a log
136:This is a new log
138 This is a new log
输出:
123:Thisisalog
136:This is a new log
解释:第二条“123:This is a log”以及”138:This is anew log”被抑制,抑制原因为满足“相同日志抑制规则 - 输入:
11
10001:This is log 1
10001:This is log 2
10001:This is log 3
10001:This is log 3
10002:This is log 4
10002:This is log 5
10002:This is log 6
10003:This is log 7
10003:This is log 8
10003:This is log 9
10005:This is log 10
输出:
10001:This is log 1
10001:This is log 2
10001:This is log 3
10002This is log 4
10002:This is log 5
10002:This is log 6
10003:This is log 7
10003:This is log 8
10003:This is log 9
解释: 第二条”10001:This is log 3”以及”10005:Thisis log 10”被抑制(前者满足“相同日志帅制条件,后者满足“相似日志抑制条件”)
- 输入:
- 提示:两条抑制规则是”或”的关系,满足其一,即做抑制。已被抑制的日志不纳入统计。
实现思路
首先对一条日志需要分割为时间和日志内容两部分,可使用Map集合容纳,时间用于判断是否在有效时间内是否需要对相同日志或者相似抑制进行抑制,日志内容用于匹配相同日志,若已经在集合中记录了相同的日志内容,如果在时间范围内则抑制,即不允许输出;日志内容还需去除数字,进行相似匹配并计数,需要一个map集合记录相似内容出现次数以及一个map集合记录相似内容出现的时间(键均为相似日志内容,方便找值匹配),满足数量条件且在时间范围内则抑制,即不允许输出
代码实现
含详细注释
package HuaweiTest2_5_26;
import java.util.*;
public class Test1 {
public static void main(String[] args) {
//输入
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.nextLine();
List<String> logs = new ArrayList<>();
for (int i = 0; i < n; i++) {
logs.add(sc.nextLine());
}
//获得输出结果
List<String> result = suppressLogs(logs);
for (String log : result) {
System.out.println(log);
}
}
public static List<String> suppressLogs(List<String> logs) {
//存储输出结果
List<String> result = new ArrayList<>();
// 存储相同日志的最后一个时间戳
Map<String, Integer> sameLogCount = new HashMap<>();
// 存储相似日志的计数器
Map<String, Integer> similarLogCount = new HashMap<>();
// 存储相似日志的最后一个时间戳
Map<String, Integer> similarLogTimestamp = new HashMap<>();
for (String log : logs) {
//遍历每一个输入日志条
String[] parts = log.split(":");
// 获得时间戳
long timestamp = Long.parseLong(parts[0]);
// 获得日志内容
String content = parts[1];
// 去除日志中的数字
String similarContent = content.replaceAll("\\d+", "");
boolean suppressed = false;
// 相同日志抑制
if (sameLogCount.containsKey(content)) {
// 有存放一样的日志内容
// 得到存放的日志内容的时间
int lastTimestamp = sameLogCount.get(content);
if (timestamp - lastTimestamp < 10) {
// 在10ms内,抑制
suppressed = true;
} else {
// 超时了没事,重复无所谓
sameLogCount.put(content, (int) timestamp);// 这里覆盖了,内容一样但是时间更新了
}
} else {
// 这条日志内容没存过,存进去
sameLogCount.put(content, (int) timestamp);
}
if (!suppressed && similarLogCount.containsKey(similarContent)) {
// 之前存有相似日志
// 取得相似出现次数
int count = similarLogCount.get(similarContent);
// 取得存放相似时间
int lastTimestamp = similarLogTimestamp.get(similarContent);
if (timestamp - lastTimestamp < 100) {
if (count >= 9) {
suppressed = true;
} else {
similarLogCount.put(similarContent, count + 1);
}
} else {
//已经超时了,前面的数据计数作废,重新计数和记录时间
similarLogCount.put(similarContent, 1);
similarLogTimestamp.put(similarContent, (int) timestamp);
}
} else if (!(similarLogCount.containsKey(similarContent))) {
// 没有相似,即只出现一次,存放次数
similarLogCount.put(similarContent, 1);
// 没有相似,存放时间
similarLogTimestamp.put(similarContent, (int) timestamp);
}
if (!suppressed) {
//不受抑制,加入result
result.add(log);
}
}
return result;
}
}