如何在記錄異常日志的時候包含源代碼文件名和行號等信息


前言

作為一個程序員,你的相當一部分時間可能會用在調試。不知道大家是否同意,異常處理(Exception Handling)是一個看似簡單,但是又極難做好的工作。當然,現在已經有一些業界經驗以及框架(例如Enterprise Library中的Exception Handling Application Block)可供參考和使用,這些框架可以幫助我們較為靈活地配置,處理或者記錄異常。我今天要跟大家分享的一個話題是,如何在記錄異常的時候,包含源代碼文件名和行號等有用信息。如果有這些信息,我們將能更加簡單地定位到問題所在。

 

案例演示

為了講解這個內容,我准備了一個簡單的項目來做演示,如下所示

image

實際上,這個Solution中有兩個項目,一個是作為組件的ClassLibrarySample

   1:  using System;
   2:   
   3:  namespace ClassLibrarySample
   4:  {
   5:      public class Test
   6:      {
   7:          public void MyMethod(int a, int b) {
   8:              try
   9:              {
  10:                  Console.WriteLine(b/a);
  11:              }
  12:              catch (Exception ex)
  13:              {
  14:                  Console.WriteLine(ex.Message);
  15:              }
  16:          }
  17:      }
  18:  }
 

 

另一個是作為調用程序的ConsoleApplicationSample

   1:  using System;
   2:   
   3:  namespace ConsoleApplicationSample
   4:  {
   5:      class Program
   6:      {
   7:          static void Main(string[] args)
   8:          {
   9:              var t = new ClassLibrarySample.Test();
  10:              t.MyMethod(0, 1);//這個調用會出錯,因為會發生除零錯誤
  11:              Console.Read();
  12:          }
  13:      }
  14:  }

這個程序運行起來肯定就是會報告異常,然后被捕捉到,我們在主程序上面可以看到如下的輸出

image

我們都知道,這樣的異常消息可能對我們幫助不是很大,尤其是如果源文件中代碼有成百上千行,那么如果不能快速定位到可能是哪一行出了這個異常,那么看起來調試和排錯都會很難。

那么是否有辦法在異常消息中,得到源代碼文件的一些信息呢?事實上是可以做到的,你只要像下面這樣修改即可:使用了StackTrace這個類型

   1:  using System;
   2:  using System.Diagnostics;
   3:   
   4:  namespace ClassLibrarySample
   5:  {
   6:      public class Test
   7:      {
   8:          public void MyMethod(int a, int b) {
   9:              try
  10:              {
  11:                  Console.WriteLine(b/a);
  12:              }
  13:              catch (Exception ex)
  14:              {
  15:                  Console.WriteLine(ex.Message);
  16:                  //通過如下代碼來記錄異常詳細的信息
  17:                  var trace = new StackTrace(ex, true).GetFrame(0);
  18:                  Console.WriteLine("文件名:{0},行號:{1},列號:{2}", trace.GetFileName(), trace.GetFileLineNumber(), trace.GetFileColumnNumber());
  19:              }
  20:          }
  21:      }
  22:  }

這樣一來,我們再進行調試的時候,就可以看到更加詳細的信息了。

image

大家可能會很好奇,這個信息是怎么給我們的呢?其實,要想實現這個功能,必須滿足一個前提條件,就是必須有ClassLibrarySample這個組件對應的調試符號文件(pdb)。

image

如果我將這個文件刪除掉,會怎么樣呢?

image

我們看到,如果沒有pdb文件,則輸出的信息是空白的。

所以,如果你想使用這個技術來記錄這些與源代碼有關的詳細信息,需要確保在部署應用程序的時候,將有關組件的pdb文件也一起部署

如果是私有部署的話,那么要做到這一點是不難的,打包的時候,將pdb文件一起包含進去就可以了。但如果這個組件是公有部署(部署到GAC) 的話,就需要額外的一些步驟。

為了將程序集部署到GAC,我們首先需要對其進行強名稱簽名。

image

然后,通過gacutil這個命令行工具,可以手工地將其添加到GAC中

image

接下來,為了讓主程序使用GAC中這個組件,而不是程序根目錄下面的那個。我們需要對引用做一個設置:Copy local設置為false

image

再次運行主程序的話,我們會得到如下的輸出

image

還是沒有與源代碼有關的詳細信息,這是因為注冊到GAC的程序集默認都是沒有pdb文件的。他們一般在下面這樣的目錄里面

image

【備注】.NET Framework 4.0這個版本中對於GAC的路徑做了調整,不再是原先的c:\windows\assembly目錄了

所以,如果需要的話,你可以將pdb文件,手工(或者通過腳本)復制到這個目錄,例如

image

這樣的話,就可以在運行主程序的時候,得到與源代碼有關的詳細信息了。

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM