我正在尝试解析日志文件。我需要帮助来检查请求和响应之间的时差。基本上超过10秒的请求数。以下是该文件的摘录:
16/08/29-03:20:39.538 << 1250 REQUEST COUNTER="1"
16/08/29-03:20:39.542 << 1250 REQUEST COUNTER="2"
16/08/29-03:20:39.656 >> 2250 RESPONSE COUNTER="1"
16/08/29-03:20:39.655 >> 2250 RESPONSE COUNTER="2"
此文件可包含约300万条记录。我想用BufferedReader读取它,读一行然后检查是否&#34; COUNTER&#34;行中存在请求时间和计数器的值,然后在整个文件中搜索相同的计数器值以获得响应时间,然后检查差异。
我需要帮助存储时间和检查差异。还有,有没有更好的方法?
BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)));
String line;
while((line = reader.readLine()) != null) {
if(line.contains("COUNTER")) {
String[] tokens = line.split("\\s+");
Date date = new SimpleDateFormat("yy/mm/dd-HH:mm:ss.SSS").parse("16/08/29-12:42:48.167");
//this is not storing the correct value
}
答案 0 :(得分:2)
我会采用一次读取日志文件的方法,并使用HashMap跟踪请求/响应。映射键是计数器,映射值是请求的日期。要节省内存,请在收到响应时从地图中删除项目。使用Java的pattern matching来确定它是请求还是响应以及获取计数器ID和日期。
以下是一个例子:
final static long EXPIRED_MILLIS = 1000 * 10; // ten seconds
final static Pattern REQUEST_PATTERN = Pattern.compile("(.* )(<< \\d{4} )(REQUEST COUNTER=\")(\\d)(\")");
final static Pattern RESPONSE_PATTERN = Pattern.compile("(.* )(<< \\d{4} )(RESPONSE COUNTER=\")(\\d)(\")");
final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yy/MM/dd-HH:mm:ss.SSS");
List<String> getExpiredCounterList(File file) throws Exception {
Map<String,Long> requestMap = new HashMap<>();
List<String> expiredCounterList = new ArrayList<>();
try( FileReader fileReader = new FileReader(file);
BufferedReader buffReader = new BufferedReader(fileReader) )
{
String line;
while((line = buffReader.readLine()) != null) {
Matcher requestMatcher = REQUEST_PATTERN.matcher(line);
if(requestMatcher.matches()) {
addRequestToMap(line, requestMatcher, requestMap);
continue;
}
Matcher responseMatcher = RESPONSE_PATTERN.matcher(line);
if(requestMatcher.matches()) {
String expiredCounter = checkIfExpiredAndRemoveFromMap(line, responseMatcher, requestMap);
if(expiredCounter != null)
expiredCounterList.add(expiredCounter);
}
}
}
return expiredCounterList;
}
void addRequestToMap(String request, Matcher requestMatcher, Map<String,Long> requestMap) {
String counter = getCounter(request, requestMatcher, 4);
long date = getDate(request, requestMatcher, 1);
requestMap.put(counter, date);
}
String checkIfExpiredAndRemoveFromMap(String response, Matcher responseMatcher, Map<String,Long> requestMap) {
String counter = getCounter(response, responseMatcher, 4);
if( requestMap.containKey(counter) ) {
long date = getDate(response, responseMatcher, 1);
long elapsedMillis = date - requestMap.remove(counter);
if(elapsedMillis > EXPIRED_MILLIS)
return counter;
}
return null;
}
String getCounter(String line, Matcher matcher, int group) {
return line.substring(matcher.start(group), matcher.end(group));
}
long getDate(String line, Matcher matcher, int group) throws ParseException {
return DATE_FORMAT.parse(line.substring(matcher.start(group), matcher.end(group))).getTime();
}
答案 1 :(得分:1)
您在使用mm
传递月份的代码中犯了一个错误,但您应该使用MM
来传递月份值。由于m
用于表示分钟,因此您应使用代表月份的M
。有关详细信息,请参阅此document。
更正代码:
BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)));
String line;
while((line = reader.readLine()) != null) {
if(line.contains("COUNTER")) {
String[] tokens = line.split("\\s+");
Date date = new SimpleDateFormat("yy/MM/dd-HH:mm:ss.SSS").parse("16/08/29-12:42:48.167");
}
当我打印日期输出时,我得到了输出Mon Aug 29 12:42:48 IST 2016
希望这是代码的有用输出。
答案 2 :(得分:1)
您正在使用麻烦的旧旧日期时间类,现在已被java.time类取代。
实例化DateTimeFormatter
。保存在某处;无需在每次解析时实例化新的。线程安全,与旧的日期时间类不同。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uu/MM/dd-HH:mm:ss.SSS" );
解析为LocalDateTime
,因为您的输入数据没有关于时区或offset-from-UTC的信息。
LocalDateTime start = LocalDateTime.parse( input , f );
顺便说一句,您的输入使用较差的格式来序列化日期时间。相反,它们应始终采用UTC并带有明确的符号,并且应始终使用标准ISO 8601格式,例如(注意最后的Z
):
2016-01-02T12:34:56.987654321Z
如果您知道预期的偏移或时区,请应用它。否则,您的日期时间数学将使用通用的24小时工作日,忽略任何异常,例如Daylight Saving Time (DST)。
Duration
类代表一段时间。
Duration duration = Duration.between( start , stop );
Duration
个对象可以进行比较和排序,实现Comparable
。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date
,.Calendar
和&amp; java.text.SimpleDateFormat
。
现在位于Joda-Time的maintenance mode项目建议迁移到java.time。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。
大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并进一步适应Android中的ThreeTenABP(见How to use…)。
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
等。