複数のログファイルを総括してかつ、特定期間分のログを抽出するには?

現在、LinuxのJavaのログファイルから一定文字列を抽出するスクリプトをbashで組んでいるのですが、
・対象はapli.logとする。(例えばの話です)
・週1回実行する(つまり1週間分のログが対象)。
・ログファイルは一定「サイズ」でローテーションされる(apli.log.1と言うような感じ。logrotateではない)。
・ログのフォーマットはyy/mm/dd hh:mm:ss <ログ内容>で出力される。
と言う条件で作成しているのですが、grep <文字列> apli.log*でやってしまうと1週間以上になってしまいますし、apli.logだけだと1週間以内で終わってしまいます。
過去1週間分だけ抽出する何か妙案はないでしょうか。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2015/04/06 22:31:15
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:a-kuma3 No.1

回答回数4973ベストアンサー獲得回数2154

ポイント90pt

シェルスクリプトの中で Perl を使って、ログファイルの時刻を切り出して、一週間前の時刻と比較する。
例えば、こんな感じ。

#! /usr/bin/bash

    cat apli.log* | \
    perl -e '
use Time::Local;

my $now = time;
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($now);
my $today = timelocal(0, 0, 0, $mday, $mon, $year);
my $aweek_before = $today - 7*24*60*60;

while (my $line = <STDIN>) {
    if ($line =~ m/^(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/) {
        my $t = timelocal($6, $5, $4, $3, $2 - 1, $1 + 2000);
        if ($t >= $aweek_before) {
            print $line;
        }
    }
}
'

起動時刻の一週間前の午前0時よりも、ログの時刻が後だったら標準出力にログの内容を出力してます。

対象のログファイルは全ファイルとしていますが、ファイル数が多くて速度が気になるようだったら find の mtime で絞り込めば良いと思います。

    find . -name "apli.log*" -mtime -8 -print | xargs cat | \
    perl -e '
        ... 以下、同じ

"-8" は、間違いじゃないです :-)

他1件のコメントを見る
id:a-kuma3

あ、仲間。
ぼくも Perl は苦手です :-)

処理が込み入ってくると grep, sed → awk → perl って感じで考えます。
最後が python や ruby じゃなくて perl なのは、いろんな unix を触って来たからです。
自分でパッケージを組み込んで良い環境なら、ruby を入れちゃいますが、そうもいかない環境での仕事もある(というか、そっちが大半)ので、最初から入ってることが多い perl を使います(仕方なく)。

と言っても、複雑な正規表現の切り出しと、時刻の扱いくらいまでしかやりませんが。

昔の手法だと、TZ 環境変数を無理矢理ずらして、date コマンドでn日前の日付を取得する、という方法もあります。

$ TZ=JST+159 date +"%Y/%m/%d"

これと、シェルの組み込みコマンドの read を組み合わせる、という方法も無くはないんですが、

  • TZ をずらして過去日を取得する方法は、どんな環境でも正しく動くとは限らない
  • perl を使ってないけど、メンテのしづらさは負けてない

という感じで...


将来、条件が複雑になる可能性が高いなら、今から java で作っちゃう、というのもひとつの手だと思います。
もしくは、メンテできる程度までは頑張って、どうにもならなくなってから java で組むことを考えるとか。

2015/04/06 15:31:53
id:a-kuma3

これと、シェルの組み込みコマンドの read を組み合わせる、という方法も無くはないんですが、

こんな感じ。

#!/usr/bin/sh

aweek_before=`TZ=JST+159 date +"%y/%m/%d"`

cat apli.log* | \
while read ymd line
do
    if [ "$ymd" = "$aweek_before" -o "$ymd" \> "$aweek_before" ]
    then
        echo $ymd $line
    fi
done

solaris だと、これで動いたんですが、Linux だと TZ をごまかしても一日前にしか戻れませんでした (´・ω・`)

2015/04/06 16:16:35

その他の回答1件)

id:a-kuma3 No.1

回答回数4973ベストアンサー獲得回数2154ここでベストアンサー

ポイント90pt

シェルスクリプトの中で Perl を使って、ログファイルの時刻を切り出して、一週間前の時刻と比較する。
例えば、こんな感じ。

#! /usr/bin/bash

    cat apli.log* | \
    perl -e '
use Time::Local;

my $now = time;
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($now);
my $today = timelocal(0, 0, 0, $mday, $mon, $year);
my $aweek_before = $today - 7*24*60*60;

while (my $line = <STDIN>) {
    if ($line =~ m/^(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/) {
        my $t = timelocal($6, $5, $4, $3, $2 - 1, $1 + 2000);
        if ($t >= $aweek_before) {
            print $line;
        }
    }
}
'

起動時刻の一週間前の午前0時よりも、ログの時刻が後だったら標準出力にログの内容を出力してます。

対象のログファイルは全ファイルとしていますが、ファイル数が多くて速度が気になるようだったら find の mtime で絞り込めば良いと思います。

    find . -name "apli.log*" -mtime -8 -print | xargs cat | \
    perl -e '
        ... 以下、同じ

"-8" は、間違いじゃないです :-)

他1件のコメントを見る
id:a-kuma3

あ、仲間。
ぼくも Perl は苦手です :-)

処理が込み入ってくると grep, sed → awk → perl って感じで考えます。
最後が python や ruby じゃなくて perl なのは、いろんな unix を触って来たからです。
自分でパッケージを組み込んで良い環境なら、ruby を入れちゃいますが、そうもいかない環境での仕事もある(というか、そっちが大半)ので、最初から入ってることが多い perl を使います(仕方なく)。

と言っても、複雑な正規表現の切り出しと、時刻の扱いくらいまでしかやりませんが。

昔の手法だと、TZ 環境変数を無理矢理ずらして、date コマンドでn日前の日付を取得する、という方法もあります。

$ TZ=JST+159 date +"%Y/%m/%d"

これと、シェルの組み込みコマンドの read を組み合わせる、という方法も無くはないんですが、

  • TZ をずらして過去日を取得する方法は、どんな環境でも正しく動くとは限らない
  • perl を使ってないけど、メンテのしづらさは負けてない

という感じで...


将来、条件が複雑になる可能性が高いなら、今から java で作っちゃう、というのもひとつの手だと思います。
もしくは、メンテできる程度までは頑張って、どうにもならなくなってから java で組むことを考えるとか。

2015/04/06 15:31:53
id:a-kuma3

これと、シェルの組み込みコマンドの read を組み合わせる、という方法も無くはないんですが、

こんな感じ。

#!/usr/bin/sh

aweek_before=`TZ=JST+159 date +"%y/%m/%d"`

cat apli.log* | \
while read ymd line
do
    if [ "$ymd" = "$aweek_before" -o "$ymd" \> "$aweek_before" ]
    then
        echo $ymd $line
    fi
done

solaris だと、これで動いたんですが、Linux だと TZ をごまかしても一日前にしか戻れませんでした (´・ω・`)

2015/04/06 16:16:35
id:blue_star22 No.2

回答回数297ベストアンサー獲得回数12

ポイント10pt

いや、だからgrepをふたつかませればいいでしょう。|で。項目1で日時、項目2で目当てのフレーズ。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません