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);
}
}
}
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));
}
}
}
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模式下面上述代码才能生效,但作为一个折中,基本上是满足项目要求了。