• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:die関数のエラー出力先について)

die関数のエラー出力先について

このQ&Aのポイント
  • die関数を使ってエラー出力先を指定する方法について質問があります。
  • Perlスクリプトでimapサーバの死活監視を行い、エラー発生時に任意のファイルにエラー内容を出力したいと考えています。
  • die関数は標準エラー出力にエラー内容を出力するため、任意のファイルに出力する方法を知りたいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.7

すいません、No.6の記述に間違いを発見しました。 $is_open = open my $fh, ">>", $logfile;    ↓   ↓訂正 $is_open = open $fh, ">>", $logfile;

taikimuru
質問者

お礼

ryu_chan様 貴重なご意見をたくさんありがとうございます。 今回はevalを用いて要件を実現することにしましたが、 サブルーチンでdieを捕捉するという手法(考え方)、 非常に勉強になりました。 ありがとうございました! これから検証して実際の動きをみながら作成したいと思います。

その他の回答 (7)

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.8

> eval { > my $imap = Mail::IMAPClient->new( > Server => $hostname, > User => $username, > Password => $password, > Timeout => 5, > ) or die "1 \n"; > my $folders = $imap->folders or die "2 \n"; > $imap->logout(); > > # ); > }; No2 です。「全体を」と書いたので、誤解を与えたかもしれません。「質問に書かれていたコード全体」という 意味です。上のコードの場合、or die "1 \n"; の次の行で eval を終了する必要があります。new() に失敗した場合は、 次の2行の $imap->folders と $imap->logout() を実行してはならないからです。また、new() に失敗した場合の エラー処理は、直後に行う必要があります。 my $imap; eval { $imap = Mail::IMAPClient->new( Server => $hostname, User => $username, Password => $password, Timeout => 5, ) or die "1 \n"; }; if ($@) { open (FILE, ">>$logfile") or die "$!"; $data = localtime; print FILE "$data FAILURE:$hostname port:143(imap4) failed. \n"; close (FILE); } else { my $folders = $imap->folders or die "2 \n"; $imap->logout(); ... もう1つですが、die "1 \n" という書き方は、何ら有益な情報を含んでいず、あまり適切とはいえません。 失敗の原因や失敗した行番号が必要なければ、eval や die を使わずに unless ($imap) { エラー処理 } とすることもできます。

taikimuru
質問者

お礼

kumoz様 「スクリプトををご確認いただいて気になることがありましたら・・・」 などと図々しく確認をお願いしてしまったにもかかわらず、 適切な回答アドバイスをいただきありがとうございます! ご教示いただいたevalの使い方でこれから検証し、 より精度の高い監視スクリプトを作成したいと思います。

  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.6

>その関数の中のdieを捕捉してエラーメッセージを$logfileに出力する、 >ということは可能なのでしょうか??? そのエラーメッセージを書き込むためのopen処理でまたエラーが出たら・・・ ってなると永遠に続きそうですね^^; 例えば以下のように、open処理を何回か繰り返して行い、ダメな場合はあきら めるとかはいかかでしょうか? my $try_count = 5; my ($fh, $is_open); for ( 1..$try_count ) { $is_open = open my $fh, ">>", $logfile; last if $is_open; sleep 1; } if ( $is_open ) { print {$fh} "$date:@_"; close $fh; } もっといい方法を誰かが提示してくれるかもしれません。

  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.5

シグナルの無効化(デフォルト状態に戻す)は、以下でもいいようです。 (互換性からこちらのほうがいいのかしら) $SIG{__DIE__} = 'DEFAULT'; ところで、以下のようにエラー処理をする関数を作るのではダメなのでしょうか? sub error { open my $fh, ">", "error.log"; print {$fh} @_; close $fh; die @_; } my $imap = Mail::IMAPClient->new( Server => $hostname, User => $username, Password => $password, Timeout => 5, ) or error "Cannot connect to $hostname imap:143. $!";

taikimuru
質問者

お礼

ryu_chan様 早速の追加回答ありがとうございます! 教えていただいた方法をもとに検証してみたところ、 以下のスクリプトでdieの標準エラー出力を任意のファイルに出力できました! #################################### my $logfile = "/var/log/imap4.log"; sub error { my $date = localtime; open my $fh, ">>", "$logfile"; print {$fh} "$date:@_"; close $fh; die @_; } my $imap = Mail::IMAPClient->new( Server => $hostname, User => $username, Password => $password, Timeout => 5, ) or error "Cannot connect to $hostname imap:143.$!\r\n"; $imap->logout(); exit ##################################### ちなみに、errorという関数の中で、 $logfileがopenできなかったことを考慮してor die処理を入れたとした場合、 その関数の中のdieを捕捉してエラーメッセージを$logfileに出力する、ということは可能なのでしょうか???

  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.4

その通りです。 dieを実行する前にシグナルを定義しておきます。 スコープを作って、dieを捕捉する範囲を限定するといいかもしれません。 { local $SIG{__DIE__} = sub { open my $fh, ">", "data.txt"; print {$fh} @_; close $fh; }; die "just die"; } あるいは、捕捉すべきdieがなくなった段階でdeleteするとかでしょうか。 delete $SIG{__DIE__};

  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.3

__DIE__擬似シグナルを用いて、dieをトラップするのはどうでしょうか? $SIG{__DIE__} = sub { open my $fh, ">", "error.log"; print {$fh} @_; close $fh; };

taikimuru
質問者

お礼

ryu_chan様 回答ありがとうございます。 教えて頂いた方法について 私の認識に間違いがないか確認させてください。 ◆私の認識 dieのシグナルに反応しさらにその実行結果をファイルに保存する、 という関数を用意し、スクリプト内のdieが実行される前の部分に配置しておく という理解で間違いないでしょうか。 よろしくお願します。

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.2

全体を eval ブロックで囲むと、die のエラーもトラップされて $@ にセットされると思います。 次は別の例ですが、(1) と (2) は同じエラーメッセージが表示されます。 (1) open FH, "not_exist" or die "Can't open not_exist: $!"; (2) eval { open FH, "not_exist" or die "Can't open not_exist: $!"; }; if ($@) { print $@; exit; }

taikimuru
質問者

お礼

kumoz様 ご回答ありがとうございます。 全体を eval ブロックで囲むという方法は、 ここに質問したあと私なりに色々調べて行き当たりました。 そして、以下のようなサンプルスクリプトを作成しましたところ、 期待とおりの結果がえられました。 ################################################## $logfile = "/var/log/imap4.log"; #my $imap; #my $folders; eval { my $imap = Mail::IMAPClient->new( Server => $hostname, User => $username, Password => $password, Timeout => 5, ) or die "1 \n"; my $folders = $imap->folders or die "2 \n"; $imap->logout(); # ); }; ###### Error judgment ##### if ($@) { open (FILE, ">>$logfile") or die "$!"; $data = localtime; print FILE "$data FAILURE:$hostname port:143(imap4) failed. \n"; close (FILE); } else { open (FILE, ">>$logfile") or die "$!"; $data = localtime; print FILE "$data SUCCESS:$hostname port:143(imap4) logged in. \n"; close (FILE); } exit ################################################## スクリプトをご確認いただいて気になることがありましたら、 ご指摘いただけますと幸いです。 よろしくお願します。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

やったことはないけど open(STDERR, ">/some/path/to/file"); みたいなことはできないかなぁ. 必要ならバッファリングも何とかする.

taikimuru
質問者

お礼

Tacosan様 ご回答ありがごとうございます。 open(STDERR, ">/some/path/to/file"); という方法で私のやりたいことを試すとした場合、 細かい話で恐縮ですが、 以下のようなスクリプトですと、 my $imap = Mail::IMAPClient->new( Server => $hostname, User => $username, Password => $password, Timeout => 5, ) or die "Cannot connect to $hostname imap:143. $!"; どの部分に挿入したらよいのでしょうか。 Perl初学者のため、基本的なことに対する理解が浅いため、 質問させていただきました。 お手数おかけしますが、ご教示いただきますと幸いです。 よろしくお願します。

関連するQ&A