前回からかなり時間が空いてしまいました。
今回はさらにテストを追加してみたいと思います。
(明らかなバグがあるので)
このプログラムの仕様をおさらいすると
ログの仕様:
yyyy-MM-dd hh:mm:ss,sss XXXX [PG名] @ [ログ出力内容]
要求仕様:
上記XXXX=INFOのものを抜き出して出力する。
というものでした。
現在実装済みのテストでは、
String[] lines = {を入力データとして使っていますが、実はこれだけではテストが足りていません。
"2009-12-14 00:00:26,340 INFO hogehoge @ abcdefg hijklmn opqrstu",
"2009-12-14 00:00:26,341 WARN fugafuga @ 11111111111111111111111",
"2009-12-14 00:00:26,341 ERROR fatal @ exception has occurred",
};
以下の場合を考えてみましょう
String[] lines = {この場合、2行目、3行目のログの種別はWARNとERRORなので、抽出されてはいけない筈です。
"2009-12-14 00:00:26,340 INFO hogehoge @ INFO=abcdefg hijklmn opqrstu",
"2009-12-14 00:00:26,341 WARN fugafuga @ INFO :11111111111111111111111",
"2009-12-14 00:00:26,341 ERROR fatal INFO = exception has occurred",
};
では、これを試すテストを追加して実施してみましょう。
/**
* 抽出する行のログの中身にINFOを含む場合
* @throws Exception 例外発生時
*/
@Test
public void testMapExtract_ComplexContents() throws Exception {
String[] lines = {
"2009-12-14 00:00:26,340 INFO hogehoge @ INFO=abcdefg hijklmn opqrstu",
"2009-12-14 00:00:26,341 WARN fugafuga @ INFO :11111111111111111111111",
"2009-12-14 00:00:26,341 ERROR fatal INFO = exception has occurred",
}; map(lines);
verify(context, new Times(1)).write(new Text(lines[0]), new LongWritable(1));
verify(context, new Times(1)).write(any(Text.class), any(LongWritable.class));
}
テストはこのようになります。実行結果はどうなるでしょうか?
REDになりました。
Wanted 1 time but was 3となっています。writeメソッドが1回しか呼ばれない想定なのに3度も呼ばれたということです。
これは、LogAnalysisMapperクラスのmap()メソッド内で、INFOがvalueに含まれているものを全て出力しているからです。仕様を満たすにはどうすればいいのでしょうか?
ログの仕様:とあるので、"^[\d]{4}-[\d]{2}-[\d]{2}\s[\d]{2}:[\d]{2}:[\d]{2},[\d]{3}\sINFO\s.*"の正規表現にマッチするものを出力するとすれば良さそうです。
yyyy-MM-dd hh:mm:ss,sss XXXX [PG名] @ [ログ出力内容]
要求仕様:
上記XXXX=INFOのものを抜き出して出力する。
では実際にプログラムを書き換えてやってみます。
(上記の正規表現はそのままJavaのプログラムに貼り付けると’\’がエスケープシーケンスとして判別されてコンパイルエラーとなってしまいます。プログラム中は’\\’と記述すればコンパイルエラーは回避されます。)
map処理を以下のように書き換えました。
/**
* map処理を実行します。
* @param key キー
* @param value 値
* @param cotext コンテクスト
*/
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// if (value.toString().contains(INFO)) {
if (value.toString().matches("^[\\d]{4}-[\\d]{2}-[\\d]{2}\\s[\\d]{2}:[\\d]{2}:[\\d]{2},[\\d]{3}\\sINFO\\s.*")) {
context.write(value, new LongWritable(1));
}
}
では実行してみます。どうなるでしょうか?
見事にGREENになりました。
今日はここまでにします。