hatenob

プログラムって分からないことだらけ

Javaでtail -f

ログにエラーが記録されたら○○したい、みたいなことってよくあるので、Javaでtail -fする方法を模索中のメモ。

自分で作る

手抜きするとこんな感じ。

public static void main(String[] args) throws Exception {
  try (BufferedReader br = Files.newBufferedReader(Paths.get(args[0]))) {
    while (true) {
      String line = br.readLine();
      if (line == null) {
        TimeUnit.SECONDS.sleep(1);
      } else {
        if (line.contains("ERROR")) {
          System.out.println(line);
        }
      }
    }
  }
}

単に1行呼んで、指定の文字列にマッチしたら処理する、というもの。
ファイルの末端に達していたら、1秒待って読む、を繰り返す。
ファイルを頭から舐めてしまうので「いやそれはもういいよ」というのも拾ってしまうのがイマイチ。
あとはローテートされたらダメ。
元のファイルを読み続けてしまうみたい。

commons-ioのTailer

commons-ioにTailerという簡易なプログラムがあるのでこれを使う。
細かなオプションはさておいて、こんな感じ。

まずはリスナー。

public class ErrorListner extends TailerListenerAdapter {
  @Override
  public void handle(String line) {
    if (line.contains("ERROR")) {
      System.out.println(line);
    }
  }
}

で、main処理。

public static void main(String[] args) {
  Tailer tailer = new Tailer(new File(args[0]), new ErrorListner());
  ExecutorService es = Executors.newFixedThreadPool(1);
  es.submit(tailer);
}

割と簡単。
ファイルを先頭から読むか、末端から開始するかは選べる。
内部的にはRandomAccessFileを使っている。
ローテートしたときの振る舞いはListnerで定義できるみたいだけれど、新しいファイルに向けなおすやり方はどう書けばよいか思いつかなんだ。

とりあえず要件としては、

  • メモリ効率が良い。
  • ファイルを書いている側のプロセスに影響しない。
  • ローテートしても新しいファイルを見てくれる。

あたりかな。
今日はこのくらい。