2016-08-29 20 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を使用したコード内の1つのミスを犯してきていますが、月の値を渡すために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"); 

ご入力されたデータは、時間帯やoffset-from-UTCに関する情報がありませんので、LocalDateTimeに解析します。

LocalDateTime start = LocalDateTime.parse(input , f); 

ところで、あなたの入力は、日時をシリアライズするための形式が貧弱です。代わりに、彼らは常に明示的な表記法とUTCにする必要がありますし、常にそのような(最後にZに注意してください)などの標準ISO 8601の形式を使用する必要がありますあなたが意図したオフセットまたはタイムゾーンを知っている場合
2016-01-02T12:34:56.987654321Z

を、それを適用します。さもなければ、Daylight Saving Time (DST)のような異常を無視して、日時の計算は24時間の一般的な日で行われます。

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を参照して、詳細をご覧ください。そして、多くの例と説明のためにStack Overflowを検索してください。

java.time機能ThreeTen-BackportでJava 6 & 7に戻って、移植、さらにThreeTenABPAndroidに適合されているの多く(How to use…を参照)。

ThreeTen-Extraプロジェクトは、追加のクラスでjava.timeを拡張します。このプロジェクトは、将来のjava.timeへの追加の可能性を証明する土台です。あなたはここにいくつかの有用なクラスを見つけることができるようIntervalYearWeekYearQuarter、など多くの。