■クラッシュログを取る

何の原因か判らずにクラッシュして落ちるソフトの原因はとてもつかみにくいです
そこで、作成したアプリケーションのがソースコード上の何行目でクラッシュしたのかを検出できれば、
原因を追究するのが難しくなくなります
クラッシュする行番号を取得するために、一行おきにグローバルな変数に行番号を書き込んで行き
例外発生時にその変数の値をログに書き出してみます


▼VB.netのソースコード


Module Module1
    Sub Main()
        Try
            ErrNo = 1
            Dim ar(2) As Integer
            ErrNo = 2
            ar(2) = 10
            ErrNo = 3
            ar(3) = 10 'ここでエラーが発生する
            ErrNo = 4
        Catch errObj As Exception
            ErrLog(errObj)
        End Try
    End Sub

    Public ErrNo As Int32
    'エラー発生時にログを取る
    Public Sub ErrLog(ByVal e As Exception)
        Dim sw As System.IO.StreamWriter
        sw = New System.IO.StreamWriter("ERR.log", True, System.Text.Encoding.GetEncoding(932))
        sw.WriteLine(Now.ToString() + " ErrNo:" + ErrNo.ToString() + " : " + e.ToString())
        sw.Flush()
        sw.Close()
        MsgBox("エラーが発生しました ID=" & ErrNo.ToString, MsgBoxStyle.Critical, "アプリケーションを終了させます")
        'アプリケーションを終了させる
        End
    End Sub
End Module

上記プログラムでは ar(3) = 10 を行った直後にエラーが発生してメッセージボックスにErrNo変数の値が 表示されます

リリースビルドで実行し、保存されたログファイルをみてみると

2007/08/14 22:51:02 ErrNo:3 : System.IndexOutOfRangeException: インデックスが配列の境界外です。
   at ConsoleApplication1.Module1.Main()
ErrNo変数に3が書き込まれた後にエラーが発生していることが確認できます


しかし、ソースコード上の一行おきに変数に代入文を書くのは凄く面倒です
そこで、Perlを使って一行おきに変数に代入分を追加してみたいと思います


ソースコードの
'*******************************************************************
で囲まれた行を見つけ出し、一行おきに代入文を追加してゆきます


▼代入文を追加するPerlプログラム

crashlog.pl
--------------------------------------------------------------------

#連番をファイルから取得する
if(open ( FHandle , "< count.txt") ){
	($counter) = <FHandle>;
	close(FHandle);
}else{
	print "COUNT FILE OPEN ERR\n";
	exit;
}

$flag=0;
$counter++;

while($line=<>){
	if($line=~/'\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/){
		if($flag){
			$flag=0;
		}else{
			$flag=1;
		}
	}
	if($flag){
		print "$line";
		print "ErrNo = $counter\n";
		$counter++;
	}else{
		print "$line";
	}
}

#連番をファイルに書き込む
if(open ( FHandle , "> count.txt") ){
	print FHandle $counter;
	close(FHandle);
}else{
	print "COUNT WRITE ERR\n";
	exit;
}
--------------------------------------------------------------------

perlプログラムと同一箇所に空のcount.txtファイルを用意しておき、次のVB.netソースコードを処理してみます

▼処理前のVBのソースコード


Module Module1
    Sub Main()
        Try
            '*******************************************************************
            Dim ar(2) As Integer
            ar(2) = 10
            ar(3) = 10 'ここでエラーが発生する
            '*******************************************************************
        Catch errObj As Exception
            ErrLog(errObj)
        End Try
    End Sub

    Public ErrNo As Int32
    'エラー発生時にログを取る
    Public Sub ErrLog(ByVal e As Exception)
        Dim sw As System.IO.StreamWriter
        sw = New System.IO.StreamWriter("ERR.log", True, System.Text.Encoding.GetEncoding(932))
        sw.WriteLine(Now.ToString() + " ErrNo:" + ErrNo.ToString() + " : " + e.ToString())
        sw.Flush()
        sw.Close()
        MsgBox("エラーが発生しました ID=" & ErrNo.ToString, MsgBoxStyle.Critical, "アプリケーションを終了させます")
        'アプリケーションを終了させる
        End
    End Sub
End Module


▼コンソールからPerlにてVBのソースコードを処理します

$ cat Module1.vb | perl crashlog.pl

出力結果は次のようになります



Module Module1
    Sub Main()
        Try
            '*******************************************************************
ErrNo = 1
            Dim ar(2) As Integer
ErrNo = 2
            ar(2) = 10
ErrNo = 3
            ar(3) = 10 'ここでエラーが発生する
ErrNo = 4
            '*******************************************************************
        Catch errObj As Exception
            ErrLog(errObj)
        End Try
    End Sub

    Public ErrNo As Int32
    'エラー発生時にログを取る
    Public Sub ErrLog(ByVal e As Exception)
        Dim sw As System.IO.StreamWriter
        sw = New System.IO.StreamWriter("ERR.log", True, System.Text.Encoding.GetEncoding(932))
        sw.WriteLine(Now.ToString() + " ErrNo:" + ErrNo.ToString() + " : " + e.ToString())
        sw.Flush()
        sw.Close()
        MsgBox("エラーが発生しました ID=" & ErrNo.ToString, MsgBoxStyle.Critical, "アプリケーションを終了させます")
        'アプリケーションを終了させる
        End
    End Sub
End Module



ソースコードの
*******
に囲まれた中のコードの一行おきに行を識別するための値が書き込まれており、
これによりクラッシュの追跡が容易になると思われます。
ただ、ソースコード自体がぐちゃぐちゃして、可読性が激しく損なわれており、実際に使うのには勇気が要ります。




▲トップページ > プログラミングの実験