.net

【.net】例外のログはStackTraceよりToStringを使うべき理由

アプリケーションを開発していると、
例外発生時に、ログやコンソールにスタックトレースを出力したいというケースは多いと思います。

言語共通でスタックトレースといえば、
一般的に例外発生時のスタックをプリントするんだな、と認識できると思います。
僕は最初に何の迷いもなく、
Exception.StackTraceを使用してログ出力していました。
試しに0除算して例外を発生させてみます。

すると↓のような出力になります。

   場所 Otameshi.Form1.Calculation() 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 80
   場所 Otameshi.Form1.button1_Click(Object sender, EventArgs e) 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 50

んん?何の例外??
例外のクラス名も、メッセージもわからないではありませんか。




そうです。
.netのException.StackTraceは、
本当にスタックに入れた、ソースの呼び出し履歴しか出力してくれないのです。
メソッドではなく、プロパティだからということもありますが。

JavaのException.printStackTrace()の場合、
基本的に必要な情報はすべて出してくれますが、
.netの場合そうはいきません。

ではわざわざ、.Messageや.StackTraceなどすべて取得する必要があるのか?

いいえ、ちゃんと用意されています。
.netの場合は、Exception.ToStringで
JavaのprintStackTrace相当の内容が出力できます。

ToString()での出力↓

System.DivideByZeroException: 0 で除算しようとしました。
   場所 Otameshi.Form1.Calculation() 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 79
   場所 Otameshi.Form1.button2_Click(Object sender, EventArgs e) 場所 {プロジェクトのパス}\Otameshi\Form1.cs:行 62

欲しかったのはこれです。
なぜ、ToStringでないと取れないのかわかりませんが、
欲しい情報は取れました。

StackTraceとToStringの違いは↓の通りです。

項目名 StackTrace ToString
現在の例外をスローしたクラス名 ×
Message ×
内部例外でのToStringの呼び出し結果 ×
Environment.StackTraceの呼び出し結果

Messageはともかく、
「現在の例外をスローしたクラス名」はStackTraceに出ても良いような気がするのですがね。。。

確かにStackTraceはプロパティ、ToStringはメソッドなので、
StackTraceにMessageなどを含めるのは違う気がしますが、
「ToString」というメソッド名では、パッと見何が取れるかわかり難い気がします。

以上、StackTraceよりToString()を使用するべきの検証でした。

2 thoughts on “【.net】例外のログはStackTraceよりToStringを使うべき理由

  1. JavaのようにVMを介さない通常の(x86)実行環境において
    「スタック上に残っている」のは「関数の呼び出し履歴」であり
    例外の内容は残りません。

    Exceptionクラスのインスタンスへの参照はスタック上に載っています(インスタンス(=例外の内容)はヒープ上です)が、通常変数はスタック上に載る、という仕様(というよりこれはx86プログラミング上の標準仕様)上の都合であって
    「スタックトレース」といった場合「通常は呼び出し履歴を指し」ます。

    よって、標準的、一般的(JavaとJava以外の他の言語、ネイティブも含めた)な考え方からすると
    「スタックトレースに例外の内容が載っている」方が「不自然・非一般的な実装」と捉えるべきです。

    1. 匿名様
      おっしゃる通り、スタックトレース=呼び出し履歴という解釈が本来正しいと思います。
      私が未熟で例外発生時の原因調査で初めてスタックトレースという言葉を耳にしたので
      「スタックトレース」=「例外に関する情報が出力されるもの」という誤った捉え方をしてしまったわけです。
      ご指摘ありがとうございます、勉強になりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です