在日志文件中解析请求和响应时间

时间:2016-08-29 13:23:39

标签: java

我正在尝试解析日志文件。我需要帮助来检查请求和响应之间的时差。基本上超过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                 
            }

3 个答案:

答案 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

您正在使用麻烦的旧旧日期时间类,现在已被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.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date.Calendar和&amp; java.text.SimpleDateFormat

现在位于Joda-Timemaintenance 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的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter等。