How to: Create a Custom TraceListener

The Telerik Data Access API provides the TraceAdapter class from the Telerik.OpenAccess.Diagnostic namespace. This class can be used to trace events dynamically and process them in the code. To use the class, another class deriving from TraceListener is required. The following code-snippet shows you the custom OpenAccessTraceListener class. It derives from the abstract System.Diagnostic.TraceListener and overrides some of its methods. In this example, the tracer class writes output messages to a TextBox control and counts the executed SQL Statements. Of course, you can implement your own custom logic to integrate the tracer into your application. The most important step here is to add the tracer to the Listeners collection of the singleton Telerik.OpenAccess.Diagnostics.TraceAdapter instance. This can be done in the constructor of the class. The WriteLine method filters the messages and prints only the SQL statements. They can be easily recognized because they start with the "driver.stat.exec" string. To use the custom traces class, just create an instance and initialize it.

C#:

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Telerik.OpenAccess.Diagnostics;

namespace DOCU_CustomTraceListener
{
    public class CustomTraceListener : TraceListener
    {
        private int id;
        private int outputMessageCount;
        private TextBox outputTextBox;
        private Thread thread;

        public CustomTraceListener(TextBox textBox)
            : base("Telerik Data Access")
        {
            this.thread = Thread.CurrentThread;
            this.outputTextBox = textBox;
            this.outputMessageCount = 0;

            TraceAdapter.Instance.Level = "4";
            this.id = TraceAdapter.Instance.Listeners.Add(this);
        }

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

        public override void WriteLine(string message)
        {
            if (Object.ReferenceEquals(this.thread, Thread.CurrentThread) == false)
            {
                return;
            }

            if (message.StartsWith("driver.stat.exec", StringComparison.InvariantCultureIgnoreCase))
            {
                int selectIndex = message.IndexOf("SELECT", StringComparison.InvariantCultureIgnoreCase);
                int insertIndex = message.IndexOf("INSERT", StringComparison.InvariantCultureIgnoreCase);

                if (selectIndex == -1 || insertIndex == -1)
                {
                    return;
                }

                int outputMessageStartIndex = 0;
                if (selectIndex < insertIndex)
                {
                    outputMessageStartIndex = selectIndex;
                }
                else
                {
                    outputMessageStartIndex = insertIndex;
                }

                this.outputMessageCount++;

                string outputMessage = String.Format("{0} CustomTraceListener : {1}{2}{3}",
                    outputMessageCount.ToString(), message.Substring(outputMessageStartIndex), Environment.NewLine, Environment.NewLine);

                this.outputTextBox.Text += outputMessage;

                this.outputTextBox.SelectionStart = this.outputTextBox.Text.Length;
                this.outputTextBox.SelectionLength = 0;
                this.outputTextBox.ScrollToCaret();
            }
        }

        internal void Reset()
        {
            this.outputTextBox.Text = String.Empty;
            this.outputMessageCount = 0;
        }

        protected override void Dispose(bool disposing)
        {
            this.outputTextBox.Text += this.outputMessageCount.ToString() + " queries executed";
            base.Dispose(disposing);
        }
    }
}

VB

Imports System.Threading
Imports Telerik.OpenAccess.Diagnostics

Public Class CustomTraceListener
    Inherits TraceListener

    Private id As Integer
    Private outputMessageCount As Integer
    Private outputTextBox As TextBox
    Private thread As Thread

    Public Sub New(textBox As TextBox)
        MyBase.New("Telerik Data Access")
        Me.thread = thread.CurrentThread
        Me.outputTextBox = textBox
        Me.outputMessageCount = 0

        TraceAdapter.Instance.Level = "4"
        Me.id = TraceAdapter.Instance.Listeners.Add(Me)
    End Sub

    Public Overrides Sub Write(message As String)
        Me.WriteLine(message)
    End Sub

    Public Overrides Sub WriteLine(message As String)
        If [Object].ReferenceEquals(Me.thread, thread.CurrentThread) = False Then
            Return
        End If

        If message.StartsWith("driver.stat.exec", StringComparison.InvariantCultureIgnoreCase) Then
            Dim selectIndex As Integer = message.IndexOf("SELECT", StringComparison.InvariantCultureIgnoreCase)


            Dim insertIndex As Integer = message.IndexOf("INSERT", StringComparison.InvariantCultureIgnoreCase)

            If selectIndex = -1 OrElse insertIndex = -1 Then
                Return
            End If

            Dim outputMessageStartIndex As Integer = 0
            If selectIndex < insertIndex Then
                outputMessageStartIndex = selectIndex
            Else
                outputMessageStartIndex = insertIndex
            End If

            Me.outputMessageCount += 1

            Dim outputMessage As String = String.Format("{0} CustomTraceListener : {1}{2}{3}", _
                    outputMessageCount.ToString(), message.Substring(outputMessageStartIndex), Environment.NewLine, Environment.NewLine)

            Me.outputTextBox.Text += outputMessage

            Me.outputTextBox.SelectionStart = Me.outputTextBox.Text.Length
            Me.outputTextBox.SelectionLength = 0
            Me.outputTextBox.ScrollToCaret()
        End If
    End Sub

    Friend Sub Reset()
        Me.outputTextBox.Text = [String].Empty
        Me.outputMessageCount = 0
    End Sub

    Protected Overrides Sub Dispose(disposing As Boolean)
        Me.outputTextBox.Text += Me.outputMessageCount.ToString() + " queries executed"
        MyBase.Dispose(disposing)
    End Sub

End Class

See Also

How to: Trace SQL Statements Generated by OpenAccessContext
How to: Enable Tracing and Logging with the Telerik Data Access Visual Designer