Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Perl logging

5,919 views

Published on

Published in: Technology
  • Be the first to comment

Perl logging

  1. 1. Perl ロギング<br />print から Log::Dispatch の拡張まで<br />2010/08/07 Hokkaido.pm #1<br />By keroyon@cpan.org<br />Hokkaido.pm #1<br />
  2. 2. 概略<br />ログのあれこれについて語ります。<br />対象は Perl 入門者です。※ 後半は初級者向けかも<br />何でログなのか<br />必須知識の割には、あまり言及されないみたいなので。<br />※ 定番サイト、定番本、グーグルで全滅<br />ログ吐く方法すら分からないとあっては、Perl採用への道が遠退きそうなので。<br />内容<br />ログ出力のためのPerlの基礎知識<br />モジュールを使ったログ出力<br />業務要件に合わせたモジュールの拡張<br />Hokkaido.pm #1<br />
  3. 3. Perlロギング その1“面倒な”前提知識を再確認<br />Hokkaido.pm #1<br />モジュールを使わないでやってみる<br />
  4. 4. debug レベル[変数の確認とか]<br />Hokkaido.pm #1<br />
  5. 5. プリント文デバッグは永劫不滅です<br />use utf8;<br />BEGIN { binmodeSTDOUT, ':utf8'; }<br />my $hoge = 'hoge';<br />print "hogeは'${hoge}'です ";<br />↓<br />hogeは'hoge'です<br />※デバッガは lvalueに関するバグがあるよ!<br />Hokkaido.pm #1<br />
  6. 6. Data::Dumper はちょっと不便<br />use utf8;<br />use Data::Dumper;<br />BEGIN { binmode STDOUT, ':utf8'; }<br />my $hoge = { key => '値' };<br />print Dumper($hoge);<br />↓<br />$VAR1 = {<br /> 'key' => "x{5024}"<br />};<br />Hokkaido.pm #1<br />
  7. 7. YAML::Syck だといい感じ<br />use utf8;<br />use YAML::Syck;<br />use feature qw(say);<br />BEGIN { <br />$YAML::Syck::ImplicitUnicode = 1;<br />binmode STDOUT, ':utf8';<br />}<br />say Dump($hoge);<br />↓<br />---<br />key: 値<br />※YAML も 0.71でUTF8文字化けしなくなったよ!<br />Hokkaido.pm #1<br />perlcriticrc<br />[Variables::ProhibitPackageVars]<br />add_packages = YAML::Syck<br />
  8. 8. info レベル[進捗の確認とか]<br />Hokkaido.pm #1<br />
  9. 9. 処理の終了と開始とか<br />say '[info] 処理A開始 ' <br /> . Time::Piece::localtime->cdate;<br /> $ ./hoge.pl >> ~/info.log<br />$ cat ~/info.log<br />↓<br />[info] 処理A開始 Sun Aug 1 13:29:31 2010<br />※5.10 から Time::Piece がコア入りしたよ!<br />Hokkaido.pm #1<br />
  10. 10. warning レベル[不穏な動きを警告]<br />Hokkaido.pm #1<br />
  11. 11. STDERR warn carp<br />use utf8;<br />BEGIN { binmode STDERR, ':utf8'; }<br />say STDERR'なんかエラーだYO! ';<br />warn 'なんかエラーだYO! '; # 行番号<br />carp 'なんかエラーだYO! '; # スタックトレース<br />$ ./hoge.pl 2>>warn.log >>debug.log<br />$ ./hoge.pl >>all.log 2>&1<br />※ うるさい時には、$Carp::Internal{'パッケージ名'}++<br />Hokkaido.pm #1<br />
  12. 12. error/critical レベル[断末魔の処理]<br />Hokkaido.pm #1<br />
  13. 13. exit die croak<br />exit 1; <br />erronoを直指定。何を言ってるのか分かりづらい<br />ジョブネット組む時に使ったりする<br />die "うぎゃぁ~。銃でやられた! ";<br />原因が分かりやすい。単に die すると 255 で固定<br />croak "やられた!かくかくしかじか"; <br />死んだ経緯をしゃべる。スタックトレースつき<br />Hokkaido.pm #1<br />
  14. 14. 終了ステータスの変更:$SIG{__DIE__}<br />捕捉してフックする<br />$SIG{__DIE__} = sub {<br /> my $error = shift;<br /> if ($error =~ m{^hello}xms) {<br />$! = 100;<br /> }<br /> die $error;<br />};<br />Hokkaido.pm #1<br />
  15. 15. 終了ステータスの変更:$ERRNO<br />$! = 100;<br />die '死亡…';<br />use Englishqw(-no_match_vars);<br />$ERRNO = 100;<br />die '死亡…';<br />※-no_match_varsをつけないと Damian 先生に怒られるよ!<br />Hokkaido.pm #1<br />
  16. 16. Perlロギング その2Log::Dispatch::* の利用<br />Hokkaido.pm #1<br />
  17. 17. Log::Dispatch<br />Hokkaido.pm #1<br />
  18. 18. Log::Distachとは<br />ログの出力先を、標準エラー/ファイル/メール/DB/Syslog/Twitterなどに自在に切り替えられる<br />簡単に拡張ができるように設計されている<br /> ↓<br />拡張モジュールが豊富<br />$cpanpm ^Log::Dispatch::<br />50 個以上ヒット!<br />miyagawa氏の名前とかもある<br />Hokkaido.pm #1<br />
  19. 19. 簡単な例:とりあえずファイルに<br />use Log::Dispatch;<br />use Log::Dispatch::File;<br />my $log = Log::Dispatch->new;<br />$log->add(<br />Log::Dispatch::File->new(<br /> name => 'file_debug',<br />min_level => 'debug',<br />max_level => 'debug',<br /> filename => 'debug.log',<br /> mode => 'append',<br /> newline => 1,<br /> )<br />);<br />$log->debug('[debug] デバッグ情報 [' . Time::Piece::localtime->cdate . ']');<br />Log::Dispatch::Outputのサブクラスを指定<br />Hokkaido.pm #1<br />
  20. 20. 簡単な例:標準エラーに追加<br />$log->add(<br />Log::Dispatch::Screen->new(<br /> name => 'screen',<br />min_level => 'debug',<br /> newline => 1,<br />stderr => 1,<br /> )<br />);<br />$log->debug('[debug] デバッグ情報 [' . Time::Piece::localtime->cdate . ']');<br />L::D::Screen を継承した<br />L::D::Screen::Color みたいなものもある<br />Hokkaido.pm #1<br />
  21. 21. Log::Dispatch::Config<br />Hokkaido.pm #1<br />
  22. 22. Log::Dispatch::Configとは<br />Log::Dispatch のサブクラス<br />(miyagawaプロダクト)<br />ログ設定を別ファイルに分離できる<br />出力書式を自由に設定できる<br />$log->debug('[debug] デバッグ情報 [' .<br />Time::Piece::localtime->cdate . ']');<br />↓ シンプル!<br />[%p] %m [%d]<br />$log->debug('デバッグ情報')<br />設定ファイルの形式は、YAML、INIファイルなどから選べる<br />Hokkaido.pm #1<br />
  23. 23. コード部分<br />初期化は、new -> add でなく、configure -> instance<br />use utf8;<br />use Log::Dispatch::Config;<br />use Log::Dispatch::Configurator::YAML;<br />BEGIN { binmode STDERR, ':utf8'; }<br />my $log_config=<br />Log::Dispatch::Configurator::YAML->new('./log_conf.yaml');<br />Log::Dispatch::Config->configure($log_config);<br />my $log = Log::Dispatch::Config->instance;#new じゃない<br />$log->debug('デバッグ情報');<br />$log->info('インフォ。');<br />Hokkaido.pm #1<br />
  24. 24. 設定ファイル(YAMLの例)<br />screen_color:<br /> class: Log::Dispatch::Screen::Color<br />min_level: debug<br /> newline: 1<br /> color:<br /> info:<br /> text: green<br /> warning:<br /> text: yellow<br /> error:<br />text: red<br />dispatchers:<br /> - file_debug<br /> - screen_color<br />file_debug:<br /> class: Log::Dispatch::File<br />min_level: debug<br />max_level: debug<br /> filename: debug.log<br /> mode: append<br /> newline: 1<br /> format: [%d] [%p] %m at %F:%L<br />サブクラスの追加属性<br />Hokkaido.pm #1<br />
  25. 25. Log::WarnDie<br />Hokkaido.pm #1<br />
  26. 26. Log::WarnDieとは<br />昔は、Log::Dispatch::WarnDieという名前だった<br />warn|die|STDERRを Log::Dispatch、Log::Log4Perl に統合する<br />warn、carp、cluck を warning レベルに自動出力<br />die、croak、confess を error レベルに自動出力<br />use Log::WarnDie $log; とするだけで有効になり、既存コードの変更は不要<br />Hokkaido.pm #1<br />
  27. 27. 簡単な例<br />use Log::Dispatch;<br />use Log::Dispatch::File;<br />use Log::WarnDie; # 一回 use しといて<br />my $log = Log::Dispatch->new;<br />$log->add( Log::Dispatch::Screen->new(<br /> name => 'screen',<br />min_level => 'debug',<br />));<br />use Log::WarnDie$log; # インスタンスを与えてもう一回 use<br />warn 'warning!';<br />die 'died…';<br />Hokkaido.pm #1<br />
  28. 28. Perlロギング その3Log::Dispatch::* の拡張<br />Hokkaido.pm #1<br />
  29. 29. Log::Dispatch::* の拡張 #1Log::Dispatch::Email:*を拡張してみよう<br />Hokkaido.pm #1<br />
  30. 30. Log::Dispatch::Email とは<br />L::D::Output のサブクラス。さらにその Email を継承したクラスが複数あり、ログをメールに出力してくれる。<br />サブクラス達(多過ぎ!)<br />Log::Dispatch::Email::EmailSend<br />Log::Dispatch::Email::MIMELite<br />Log::Dispatch::Email::MailSend<br />Log::Dispatch::Email::MailSender<br />Log::Dispatch::Email::MailSendmail<br />欠点<br />モダンじゃない<br />日本語メールが文字化けして嫌な目にあう<br />じゃあ、モダンで文字化けしないのを作ってしまおう!<br />Hokkaido.pm #1<br />
  31. 31. Log::Dispatch::Email::EmailSender<br />モダンなメール送信クラス Email::EmailSenderを利用してメールを送る<br />エンコードを指定できるので文字化けしない<br />Email::EmailSender::Transport::Sendmailの他に、Email::EmailSender::Transport::SMTP にも対応させる<br />L::D::Email を継承して、send_emailメソッドをオーバーライドすれば完了<br />Hokkaido.pm #1<br />
  32. 32. コンストラクタ:%p -> $self へ<br />sub new {<br />    my $proto = shift;<br />    my $class = ref $proto || $proto;<br />    my %p = @_;<br />    my $self = $class->SUPER::new(%p);<br />    $self->{use_transport_smtp} = delete $p{use_transport_smtp};<br />    $self->{host} = delete $p{host};<br />    $self->{port} = delete $p{port};<br />    $self->{ssl} = delete $p{ssl};<br />    $self->{sasl_username} = delete $p{sasl_username};<br />    $self->{sasl_password} = delete $p{sasl_password};<br />    return $self;<br />}<br />※ 勝手に拡張したパラメータは、delete で即座に消すのが流儀らしい<br />Hokkaido.pm #1<br />
  33. 33. send_emailメソッド<br />sub send_email {<br />    my $self = shift;<br />    my %p = @_;<br />    my $to_str = join ',', @{ $self->{to} };<br />    my $email = _create_email({<br />            from => $self->{from},  to => $to_str,  subject => $self->{subject},<br />            header_encode => $self->{header_encode} || 'MIME-Header-ISO_2022_JP',<br />            body_encode => $self->{body_encode} || 'iso-2022-jp',<br />            body => $p{message},<br />    });<br />… 省略 …<br />    sendmail( $email, $transport, { to => $self->{to} } );<br />}<br />※$self からパラメータを受け取り、実際にメールを送信するコードを記述します。<br />例外処理とTransport::SMTPは省略してます<br />Hokkaido.pm #1<br />
  34. 34. _create_emailメソッド<br />sub _create_email {<br /> my $opt = shift;<br /> my $enc1 = $opt->{header_encode};<br /> my $enc2 = $opt->{body_encode};<br /> my $email = Email::MIME->create(<br /> header => [<br /> From => encode( $enc1, $opt->{from} ),<br /> To => encode( $enc1, $opt->{to} ),<br /> Subject => encode( $enc1, $opt->{subject} ),<br /> ],<br /> attributes => {<br />content_type => 'text/plain',<br />charset => $enc2,<br /> encoding => '7bit',<br /> },<br /> body => encode( $enc2, $opt->{body} ),<br /> );<br /> return $email;<br />}<br />Email::MIME->create して、return してるだけ。<br />Hokkaido.pm #1<br />
  35. 35. 使い方:Sendmail<br />use Log::Dispatch;<br />use Log::Dispatch::Email::EmailSender;<br />my $log =Log::Dispatch->new;<br />$log->add(<br /> Log::Dispatch::Email::EmailSender->new(<br />min_level => 'emerg',<br />from => 'logger@example.com',<br />to => [ qw( foo@example.com bar@example.org ) ],<br />subject => 'Big error!',<br />header_encode => 'MIME-Header-ISO_2022_JP',<br />body_encode => 'iso-2022-jp‘<br /> )<br />);<br />$log->emerg("Something bad is happening");<br />Hokkaido.pm #1<br />
  36. 36. 使い方:SMTP<br />Log::Dispatch::Email::EmailSender->new(<br />min_level => 'emerg',<br />from => 'logger@example.com',<br />to => [ qw( foo@example.com bar@example.org ) ],<br />subject => 'Big error!',<br />header_encode => 'MIME-Header-ISO_2022_JP',<br />body_encode => 'iso-2022-jp‘,<br />use_transport_smtp => 1,<br />host => [your smtp host],<br /> port => [your smtp port number],<br />sasl_username => [your username],<br />sasl_password => [your password],<br />)<br />Hokkaido.pm #1<br />
  37. 37. 補足など<br />インストール<br />$ cpanf –m Log::Dispatch::Email::EmailSender<br />$cpanf –mdi Log::Dispatch::Email::EmailSender<br />欠点<br />SSL オプションを使えない<br />(gmailアカウント使えない)<br />メール送信エラー時のリトライがない<br />他のEmail::Sender::Transport::* に未対応<br />添付ファイルとかHTMLメールとか送れない<br />バグ報告、パッチ、要望など<br />http://github.com/keroyonn/p5-Log-Dispatch-Email-EmailSender<br />http://rt.cpan.org/<br />keroyon@cpan.org<br />Hokkaido.pm #1<br />
  38. 38. Log::Dispatch::* の拡張 #2Log::Dispatch::Configを拡張してみよう<br />Hokkaido.pm #1<br />
  39. 39. こんなことありませんか?<br />処理速度の傾向を把握したい<br />バッチ処理で、目標とする処理時間がある<br />ランダムなデータでは目標をクリアしているが、実データで実際どうなるか分からない<br />サービスイン当初はいいが、データ増大と共に重くなるため処理時間の監視が必要<br />プロファイルの前に原因箇所にあたりをつけておきたい<br />捕捉し切れていない例外が総合テストで明らかになって、ふと大丈夫か不安になる<br />Perl の警告とプログラムの警告ログが別管理されていて、うっかり片方のチェックを忘れてしまう<br />Hokkaido.pm #1<br />
  40. 40. Log::Dispatch::Config::Watcher<br />特徴<br />関数の実行状態(時間、成否)を監視して、自動でログを出力する。特定の条件で警告ログを追加出力できる<br />フォーマットが拡張されていて、ナノセカンド単位の時間を表示したりできる<br />ひとつのアウトプット内で、条件に応じてフォーマットを切り替え可能。<br />warn と die を監視して、別フォーマットでログ出力できる。<br />欠点<br />Coro なら大丈夫だけど、AnyEventには対応していない。<br />重いかも。いや重い。<br />Hokkaido.pm #1<br />
  41. 41. 利用例:コード部分 #1<br />use Log::Dispatch::Config::Watcher;<br />use Log::Dispatch::Configurator::YAML;<br />my $config = Log::Dispatch::Configurator::YAML->new('/path/to/log.yaml');<br />Log::Dispatch::Config::Watcher->configure($config);<br />my $log = Log::Dispatch::Config::Watcher->instance;<br />$log->info('log message');<br />test1();<br />test2();<br />test3();<br />Hokkaido.pm #1<br />
  42. 42. 利用例:コード部分 #2(つづき)<br />sub test1 { <br /> $log->warn('sample warning.');<br /> sleep 4;<br />}<br />#evalされた die<br />sub test2 { <br />eval { die 'die with expected exception'; };<br /> warn $@ if $@;<br />}<br /># evalされてない die<br />sub test3 { <br /> sleep 5;<br /> die 'die with unexpected exception.';<br />}<br />Hokkaido.pm #1<br />
  43. 43. 利用例:設定ファイル #1<br />dispatchers:<br /> - screen<br />screen:<br /> class: Log::Dispatch::Screen<br />min_level: debug<br /> format: '[%p] %F:%L %m [%D{%F %T.%6N%z}]' <br /># DateTime::Format::Strptime<br /> newline: 1<br />stderr: 1<br />Hokkaido.pm #1<br />
  44. 44. 利用例:設定ファイル #2(つづき)<br />watch:<br />watch_die: 1<br />watch_only_unexpected_die: 1<br />watch_warn: 1<br />die_level: critical<br />warn_level: warning<br /> formats:<br /> start: '[%p] START:%j [%D{%F %T.%6N%z}]'<br /> end: '[%p] END:%j(%t) [%D{%F %T.%6N%z}]'<br />end_with_die: '[%p] ABNORMALLY_ENDED:%j(%e) [%D{%F %T.%6N%z}]'<br /> die: '[%p] UNEXPECTED_DIE (%e) [%D{%F %T.%6N%z}]'<br /> warn: '[%p] PERL_WARNING (%e) [%D{%F %T.%6N%z}]'<br />timeover: '[%p] TIMEOVER:%j(%t)‘<br />%j … 関数の詳細説明<br />%t … 関数の実行時間<br />%e … 警告メッセージ<br />Hokkaido.pm #1<br />
  45. 45. 利用例:設定ファイル #3(つづき)<br />watch:<br />~#2 参照(略)~<br />functions:<br />main::test1# パッケージ名に注意<br /> description: sleep 4 seconds process<br />warn_duration: 5.0 # 秒数を指定<br />notice_duration: 3.5<br />main::test3:<br /> description: sleep 5 seconds process<br />warn_duration: 4.0<br />notice_duration: 2.5<br />Hokkaido.pm #1<br />
  46. 46. 実行結果<br />素の $log->info()<br />[info] ./log.pl:13 log message [2010-07-30 15:34:16.316215+0900]<br />監視対象: test1() warn -> sleep 4;<br />[info] START:"sleep 4 seconds process" [2010-07-30 15:34:16.319123+0900]<br />[warn] ./log.pl:19 sample warning. [2010-07-30 15:34:16.320854+0900]<br />[notice] TIMEOVER:"sleep 4 seconds process"(=>00:00:04.005179167)<br />[info] END:"sleep 4 seconds process"(=>00:00:04.005179167) [2010-07-30 15:34:20.324692+0900]<br />非監視対象: test2() evalされた die<br />[warning] PERL_WARNING (die with expected exception at ./log.pl line 25.)<br />監視対象:test3() evalされない die<br />[info] START:"sleep 5 seconds process" [2010-07-30 15:34:25.328754+0900]<br />[warning] TIMEOVER:"sleep 5 seconds process"(=>00:00:05.00351812)<br />[critical] ABNORMALLY_ENDED:"sleep 5 seconds process"(die with unexpected exception. at ./log.pl line 30.) [2010-07-30 15:34:25.330754+0900]<br />Hokkaido.pm #1<br />
  47. 47. 拡張方法 #1 フック<br />create_instanceのオーバーライド<br />インスタンス生成時、設定ファイルの更新時に実行されるメソッド<br />Hook::LexWrapを利用してメソッドの起動と終了をフックする<br />$SIG{__DIE__}、$SIG{__WARN__} で die、warn をフックする<br />同一Outputクラス内でのフォーマット書き換えを実現するため、フォーマットのバックアップ->出力->フォーマットのリシュームを行う<br />Hokkaido.pm #1<br />
  48. 48. 拡張方法 #2 拡張書式<br />format_to_cbのオーバーライド<br />ログメッセージの生成時に実行されるメソッド<br />DateTime、DateTime::HiRes、DateTime::Format::Strptimeなどを利用して複雑な時刻書式に対応させる<br />正規表現でパースしているので、その部分を拡張して、拡張フォーマットに対応させる<br />ソースをコピーして上書きするという美しくない拡張<br />Hokkaido.pm #1<br />
  49. 49. 補足など<br />インストール<br />$ cpanf –m Log::Dispatch::Config::Watcher<br />$cpanf –mdi Log::Dispatch::Config::Watcher<br />欠点<br />main パッケージのメソッドにも main:: が必要<br />拡張方法が美しくない<br />$SIG{__WARN__} 書き換えによる不具合とか起こりそう<br />(たぶん)重い<br />バグ報告、パッチ、要望など<br />http://github.com/keroyonn/p5-Log-Dispatch-Config-Watcher<br />http://rt.cpan.org/<br />keroyon@cpan.org<br />Hokkaido.pm #1<br />
  50. 50. まとめ<br />Perl は意外に約束事が多い<br />PerlMongerじゃない人には丁寧に教えてあげよう<br />CPANには良いログモジュールがある<br />プロジェクト単位でログモジュールを自作してしまう前に、ちゃんと検討しよう<br />特別な事情がなければ、汎用性のあるCPANモジュールを使おう<br />CPANのモジュールは拡張性が高い<br />業務要件を満たせない場合には、薄いラッパーを作ってみるのもいいけど、モジュールの拡張にもチャレンジしてみよう<br />Hokkaido.pm #1<br />
  51. 51. ご清聴ありがとうございました<br />Hokkaido.pm #1<br />

×