読者です 読者をやめる 読者になる 読者になる

愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

Log::Handyとかそんなものをでっちあげた

Perl

Mandyではありません。Handyです。


http://github.com/zentooo/p5-log-handy


個人的にLoggerにあってほしいのは

  • 色々な場所への出し分け/同時出力が出来る(STDOUT, file, syslogくらいがとりあえずあればいいけど)
  • インタフェースが煩雑でない(例えば$self->log(level => "warn", message => "message" ...) とかダメ。使い方として$self->log->warn("message") くらいが限界)
  • ファイルを手軽にわけられる

というような機能なのだけど、最後のがあんまり満たされないので自分でつくった。

BASICS

基本的にはLog::Handler (http://search.cpan.org/~bloonix/Log-Handler-0.71/lib/Log/Handler.pm) に近い動きをする

    use Log::Handy;

    # initialize with configuration parameters

    my $log = Log::Handy->new(
        global => +{
            min_level => 'warn',
            max_level => 'critical',
        },
        outputs => +{
            screen => +{
                min_level => 'debug',
                log_to => 'STDOUT',
            },
            file => +{
                filename => 'myapp_%T{%Y%m%d}.log',
            },
            syslog => +{
                ident => 'myapp',
                facility => 'user',
                logopt => 'nowait,pid',
            }
        }
    );

    $log->warn('woofoo!');


    # add after initialization

    my $log = Log::Handy->new;

    $log->add(
        "Output::Screen" => +{ # 'screen' is alias of this
            min_level => 'warn',
            log_to => 'STDERR'
        },
    );

    $log->add(
        "+YourApp::Output::Hogehoge" => +{
            option1 => "foo",
            option2 => "bar"
        }
    );

    $log->critical('hmmmmmm');


    # initialize with config file ( perl format recommended )

    my $log = Log::Handy->load('config.pl');

    $log->debug('yeaaaaaaaaah');

filename

ちょっとキモいんだけど、filename中で %T{hoge}と書いたhogeの部分がstrftimeで置き換わる。また、%lと書いた部分がlog level(warnとかcriticalとか)で置き換わる。ログが多くなってくると、レベル別にわけたい場面が出てくるのでこれは便利。

あと、「Aの部分がどうもバグってるっぽいんだけど、今は深追いしてる時間ないしどうもよくわからない感じのコードになってるからログ出しておこう」みたいなことが現実の世界では起こったりするわけだけど、そいつだけを特定のファイルに出したい場合

$log->info("hoge", +{ filename => 'A_myapp_%T{%Y%m%d}.log' });

のようにすると、呼び出し時のオプションが効いてそこだけ別のファイルに出せる。各種設定は、globalな設定 -> output個別の設定 -> 呼び出し時の設定 の順に常に右側にオーバライドされる。

こういう場合、logを置くディレクトリを一々filenameの中に書いていくと面倒なので

  global => +{
      dirname => '/var/log'
  }

とかしておくと、logは "$dirname/$filename" な場所に吐かれるようになる。

auto dump

あとlogって、何らかの入力データとかその一部をdumpしたものをメタデータとして付与するもんだと思うけど、いちいち呼び出し側でdumpするのがめんどいので

$log->warn("request parameter =", $req->{param}, "error =", $e);

とか、複数パラメータを渡してそれらのうち文字列でないものは勝手にdump + joinしてくれる。デフォルトはData::Dump::dumpにしてるけど、例えばData::Dumperが使いたい場合はuse Data::Dumperしたうえで

dump_callback => sub {
  Dumper shift;
}

という設定を書いてやれば置き換えられる。

joinするseparatorが気に食わない場合は

separator => ', '

という設定を食わせてやればいい。

実は、パラメータの末尾(上の例の$e)がハッシュリファレンスだった場合、呼び出し時のオプションとして解釈されてしまう。このへんちょっと残念なので何とかしたい。どうすればいいだろう。

ログ抑止

testの時とかlog出したくない、とかそういうこともあるわけだけども

suppress_callback => sub {
  $ENV{TEST_YOURAPP};
}

とかしてやると、TEST_YOURAPPな時だけログを抑止できる。多分大抵の人はこういう時環境変数使うと思うんだけど、一応コールバックにした。

たぶん便利

まだちょっとバグってるかもしれないけど、気に入ったひとは使ってみてぴょん。とりあえずはgithubにおきます。というかPOD書け、俺。