.NET下一种简单的调试诊断方法

.NET下,我们可以借助于DebugTrace类对程序的执行过程进行跟踪、断点、调试、日志记录等,从而可以快速定位和排除程序故障。同时.Net提供的几个TraceListener类可以方便灵活的让我们选择信息的输出方式:日志文件,事件日志等等,但有的时候我们需要实时跟踪调试信息的输出,就像IDE的调试窗口输出,或者类似HTTPWATCH的输出。比如我们在窗体上放一个Text控件,希望通过这个控件实时查看调试信息的输出。那么能否将DebugTrace类的输出定向到这个控件中呢?答案是肯定的,通过继承TraceLister类来实现,下面的代码将调试信息输出到RichTextBox中:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;

namespace MyTraceListenerTesting
{
    
class MyTraceListener:TraceListener
    
{
        
private RichTextBox _richTextBox = null;

        
public MyTraceListener(RichTextBox richTextBox)
        
{
            
this._richTextBox = richTextBox;
            
this.NeedIndent = true;
        }


        
private delegate void WriteDelegate(string message);
        
private void WriteImpl(string message)
        
{
            
if (this.NeedIndent)
            
{
                
this.WriteIndent();
                
this.NeedIndent = true;
            }

            
this._richTextBox.AppendText(message);
            
this._richTextBox.Select(this._richTextBox.Text.Length, 0);
            
this._richTextBox.ScrollToCaret();
        }


        
public override void Write(string message)
        
{
            
//This is for thread safety
            this._richTextBox.Invoke(new WriteDelegate(this.WriteImpl), new object[] { message });
        }


        
public override void WriteLine(string message)
        
{
            
this.Write(message + Environment.NewLine);
        }

    }

}

通过上述代码可以看出,其实实现自定义的TraceLister是非常方便的,我们可以方便的根据自己的需要将日志信息输出到不同的目标位置。

测试程序如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace MyTraceListenerTesting
{
    
public partial class Form1 : Form
    
{
        
public Form1()
        
{
            InitializeComponent();
        }


        
private void f1()
        
{
            
int id = System.Threading.Thread.CurrentThread.ManagedThreadId;
            Debug.WriteLine(
"Enter f1 by thread " + id.ToString());
            Debug.Indent();
            
this.f2();
            Debug.Unindent();
            Debug.WriteLine(
"Leave f1 by thread " + id.ToString());
        }

        
private void f2()
        
{
            
int id = System.Threading.Thread.CurrentThread.ManagedThreadId;
            Debug.WriteLine(
"Enter f1 by thread " + id.ToString());
            Debug.Indent();
            
for (int i = 0; i < 100; i++)
            
{
                Debug.WriteLine(
"Working inside step "+i.ToString()+"by thread " + id.ToString());
                System.Threading.Thread.Sleep(
20);
            }

            Debug.Unindent();
            Debug.WriteLine(
"Leave f1 by thread " + id.ToString());
        }

        
private void button1_Click(object sender, EventArgs e)
        
{

            
this.f1();
        }


        
private void Form1_Load(object sender, EventArgs e)
        
{
            Debug.Listeners.Add(
new MyTraceListener(this.richTextBox1));
        }

    }

}


目前从其它线程单独调用Debug.WriteLine是没有问题的,可以正确的将信息写入界面线程的控件中,但是当多个线程同时调用Debug.WriteLine的时候,会出现死锁现象,关于TraceListener的线程安全如何处理目前还不是很清楚,需要进一步完善。

这篇文章的产生基于这样的原因:一个程序因为过于庞大复杂,需要详细记录日志以便于操作,开始的时候采用了EnterpriseLibrary,效果确实好,非常方便,但后来提出程序可能要向PDA平台迁移,因此果断舍弃EnterpriseLibrary,决定采用其他方法,经过一番考察后决定采用系统自带的Debug类和Trace类,遗憾的是Trace类只提供了Assert方法,就是说在Release版本中是无法记录调试信息的,只有在DEBUG模式下面上述代码才能生效,但作为一个折中,基本上是满足项目要求了。

原文地址:https://www.cnblogs.com/swnuwangyun/p/686289.html