如何在记录异常日志的时候包含源代码文件名和行号等信息

前言

作为一个程序员,你的相当一部分时间可能会用在调试。不知道大家是否同意,异常处理(Exception Handling)是一个看似简单,但是又极难做好的工作。当然,现在已经有一些业界经验以及框架(例如Enterprise Library中的Exception Handling Application Block)可供参考和使用,这些框架可以帮助我们较为灵活地配置,处理或者记录异常。我今天要跟大家分享的一个话题是,如何在记录异常的时候,包含源代码文件名和行号等有用信息。如果有这些信息,我们将能更加简单地定位到问题所在。

 

案例演示

为了讲解这个内容,我准备了一个简单的项目来做演示,如下所示

如何在记录异常日志的时候包含源代码文件名和行号等信息_第1张图片

实际上,这个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,我们首先需要对其进行强名称签名。

如何在记录异常日志的时候包含源代码文件名和行号等信息_第2张图片

然后,通过gacutil这个命令行工具,可以手工地将其添加到GAC中

image

接下来,为了让主程序使用GAC中这个组件,而不是程序根目录下面的那个。我们需要对引用做一个设置:Copy local设置为false

如何在记录异常日志的时候包含源代码文件名和行号等信息_第3张图片

再次运行主程序的话,我们会得到如下的输出

image

还是没有与源代码有关的详细信息,这是因为注册到GAC的程序集默认都是没有pdb文件的。他们一般在下面这样的目录里面

image

【备注】.NET Framework 4.0这个版本中对于GAC的路径做了调整,不再是原先的c:\windows\assembly目录了

所以,如果需要的话,你可以将pdb文件,手工(或者通过脚本)复制到这个目录,例如

image

这样的话,就可以在运行主程序的时候,得到与源代码有关的详细信息了。

如何在记录异常日志的时候包含源代码文件名和行号等信息_第4张图片

你可能感兴趣的:(如何在记录异常日志的时候包含源代码文件名和行号等信息)