perl大好き ファイルに書き出すタイプのデバッガ作った。caller(関数名・ファイル名が取れる)を初めて使った。実行中の配列やハッシュ、パラメータを確認できる様にした。
月曜日に、今動いている新潟県の教育関係のwebアプリに問題が見つかった。エラーチェックが甘かったためで、お客様に問題はない。プログラム自身も今まで破綻せずに動いてくれていた。ひとえにお客様がきちんと入力していてくれたおかげである。
エラーチェックは難しい。あまり厳しくすると世知辛くなり、あまり甘くすると思わぬ落とし穴となる。
恋愛と同じである(ウンウン)。
ajaxでページ推移をしないで中のdivの値を入れ替えているので色々と便利なのだけど、デバッグがしにくい。
なにせ、ブラウザに値が戻らなければ確認できない上に、途中の値の変化を追いにくい。
プログラムのどのステップで問題が発生したのか確認がしにくいのだ。
そこで、ファイルに書き出して値を見るタイプのデバッガを作ることにした。
前から作ろうと思いながらなんとなく作らなくとも、やっていけたのでそのままであった。
呼び出し元
値を用意して、参照で渡す。
デバッグしたいところに配置する
my $open_file_name="_dbug_hekimen.txt";## 書き出すファイル名 my $test="test scalar";## 変数を表示 my @test=(1,2,3);## 配列を表示 my %test=(1,"a",2,"b",3,"c");## ハッシュを表示 print_file($open_file_name,\$test,\@test,\%test);###ここで呼び出す
ユーティリティの中にサブルチンを作った
ここを呼び出す。
sub print_file{#####2019/7/15 デバッグ中のデータをファイルに書き出すルーチンを作成。 my $filename=shift; my $data_scala_ref=shift; my $array_ref=shift; my $hash_ref=shift; my $data=""; $data.=caller_string(1); $data.="========== data param =========\n"; $data.=$$data_scala_ref; $data.="\n"; $data.="========== data array no sort=========\n"; if($array_ref ne ""){ foreach my $line (@$array_ref){ $data.= $line; $data.="\n"; } } $data.="========== data hash on sort by key=========\n"; if($hash_ref ne ""){ foreach my $key (sort(keys(%$hash_ref))){ $data.= $key; $data.= " : "; $data.= $$hash_ref{$key}; $data.="\n"; } } my $empt=""; my $notempt=""; $data.="\n========== param with val =========\n"; foreach my $k (sort(keys(%p))){ my $data_w.=$k; $data_w.=" : "; $data_w.=$p{$k}; $data_w.="\n"; if($p{$k} eq ""){ $empt.=$data_w; }else{ $notempt.=$data_w; } } $data.=$notempt; $data.="\n========== caller dipth 1..10 =========\n"; foreach my $roop (1..10){ $data_path=caller_string($roop); if($data_path ne ""){ $data.="$data_path \n"; }else{ last; } } $data.="\n========== param with no val =========\n"; $data.=$empt; open my $fh, "+>", $filename or die "$!:$filename"; print $fh $data; close $fh; }
上のサブルーチンから呼び出される
callerと言う関数を初めて使った。
10階層までさかのぼってサブルーチンの名前とファイル名を呼び出してくれる(なければ表示されない)。
いつも使っているデバッガで出力されているサブルーチン名はこれで取っていたのかと納得。
sub caller_string{ my $i=shift; my $count =$i-1; my $data=""; @call_arr = caller($i); if($call_arr[1] eq ""){ return ""; }else{ if($i != 1){ $data.=$count." : "; }else{ $data.=" "; } my ($path)=$call_arr[1]=~m/.*cloud\/(.*)$/; $data.="....".$path."\n sub : "; $data.=$call_arr[3]."( line : "; $data.=$call_arr[2].")\n"; return $data; } #my ($package,$filename,$line,$subroutine,$hasargs,$wantarray,$evaltext,$is_require, $hints,$bitmask,$hinthash)=caller($i) #$i=0になると、このサブルーチンが表示される。$i=1が直接の呼び出し元
ファイルにはこういう風に書き出される。
随分楽になった。
....koubun2019/_/sys_kobun/_p/_21_kan_gak_sel/_01_program.pm
sub : main::print_file( line : 291)
========== data param =========
test scalar
========== data array no sort=========
1
2
3
========== data hash on sort by key=========
1 : a
2 : b
3 : c========== param with val =========
ac0 : load_html
ac1 : load_main
eda_no : XXXXXXXXXXXXXXXX
gak_cd : XXXXXXXXXXXXXXXX
gak_eda : XXXXXXXXXXXXXXXX
gak_pass : XXXXXXXXXXXXXXXX
kan_pass : XXXXXXXXXXXXXXXX
ken : XXXXXXXXXXXXXXXX
kubun : XXXXXXXXXXXXXXXX
p : XXXXXXXXXXXXXXXX
p_kubun : kan
page_name : c020_kan_seit
select_rb : 2========== caller dipth 1..10 =========
....koubun2019/_/sys_kobun/_p/_21_kan_gak_sel/_01_program.pm
sub : main::print_file( line : 291)
1 : ....koubun2019/_/sys_kobun/_p/_21_kan_gak_sel/_01_program.pm
sub : main::get_seito_sakuhin_arr( line : 4)
2 : ....koubun2019/_/sys_kobun/_p/_21_kan_gak_sel/_00_kan_gak_sel_bunki.pm
sub : main::make_program( line : 42)
3 : ....koubun2019/_/sys_kobun/_p/_02_load_html/_00_load_bunki.pm
sub : main::kan_gak_sel_bunki( line : 99)
4 : ....koubun2019/_/sys_kobun/_main.cgi
sub : main::load_bunki( line : 124)
========== param with no val =========
ac10 :
ac2 :
ac3 :
ac4 :
ac5 :
ac6 :
ac7 :
ac8 :
ac9 :
brk :
div :
field_tag_key :
get_env :
how :
lay :
rec_key :
sort :
val :
明日から国体の仕事で東京だ。
10月は茨城である。
masaya50.hatenadiary.jp
考えてみると10年前の新潟国体の仕事からperl使い始めたのだ。
masaya50.hatenadiary.jp
どこに縁が有るのかなどわからない。
還暦である。
もう10年頑張ろう(笑)。
masaya50.hatenadiary.jp
masaya50.hatenadiary.jp
こちらのページにお世話になりました。
ありがとうございました。