2016-08-29 91 views
0

我試圖解析日誌文件。我需要幫助來檢查請求和響應之間的時間差。基本上超過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讀取它,讀取一行,然後檢查行中是否存在「COUNTER」,存儲請求時間和計數器的值,然後在整個文件中搜索相同的計數器值以獲取響應時間,然後檢查差異。

我需要幫助來儲存時間和檢查差異。另外,有沒有更好的方法?

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     
      } 
+2

請注意,您可以爲每個匹配行使用相同的SimpleDateFormat對象,而不是每次都創建一個新對象。 – Berger

+1

只要你沒有多個線程並行處理你的文件!然後每個線程都需要自己的格式化程序。 – GhostCat

+0

在閱讀日誌文件時,我會在列表中記錄我遇到的「請求」。一旦我到達「RESPONSE」行,我會從列表中刪除相應的REQUEST,並檢查延遲是否超過10秒。 – Aaron

回答

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

您已在您所使用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希望這是你的代碼有用的輸出。

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,& java.text.SimpleDateFormat

Joda-Time項目現在位於maintenance mode,建議遷移到java.time。請參閱Oracle Tutorial。並搜索堆棧溢出了很多例子和解釋。

大部分的java.time功能後移植到Java 6 和ThreeTenABP還適於Android(見How to use…)。

ThreeTen-Extra項目擴展java.time與其他類。這個項目是未來可能增加java.time的一個試驗場。你可以在這裏找到一些有用的類,如Interval,YearWeek,YearQuarter,等等。