.NET Trace, The Only Logging Framework You’ll Ever Need – Helper Classes

By the time you have read through the previous four posts, you should be able to create end-to-end Traces for your applications:

In the first posting we introduced the new .NET (2.0+) Trace framework and talked about the features that make it a comprehensive Tracing tool. We then went on to look at more advanced usage and configuration in the second posting, particularly around the XmlWriterTraceListener and the Microsoft Service Trace Viewer. The third posting looked at Activity Tracing, Activity Propagation and WCF Activity Tracing. The fourth posting looked at how to propagate Trace information to HTTP based endpoints such as ASP.NET and ASP.NET MVC.

Using Resource Objects

You will start to see you code can become quite complex as you add Activity tracing information; this is due to having to close off any Start or Transfer Activity. To ensure you close off any Starts or Transfers, you need to make sure you catch any errors and in the finally section of the code call the appropriate Stop or Transfer back.

TraceSource traceSource = new TraceSource("DemoApp");

try
{
  traceSource.TraceEvent(TraceEventType.Start, 0, "Start activity here ...");
}
finally
{
  traceSource.TraceEvent(TraceEventType.Stop, 0, "Stop activity here ...");
}

The alternative to this approach is to use a Disposable object and call it as part of a resource object pattern. In this case, the code is much cleaner and simpler to read and implement. The following classes provide resource containers for Start and Transfer activities so that they can be encapsulated in a using statement:

TraceLogicalScope

The TraceLogicalScope class provides a simple and safe way to encapsulate a Start and Stop activity.

/// <summary>
/// Represents a Trace Start/Stop where the Start and Stop are called automatically
/// </summary>
public class TraceLogicalScope : IDisposable
{
  /// <summary>
  /// The source that we are tracing through as part of this scope
  /// </summary>
  private readonly TraceSource _traceSource;

  /// <summary>
  /// The name of the logical block that this scope represents
  /// </summary>
  private readonly string _logicalName;

  /// <summary>
  /// Constructor used to initialize the class
  /// </summary>
  /// <param name="traceSource">The source that we are tracing through as part of this scope</param>
  /// <param name="logicalName">The name of the logical block that this scope represents</param>
  public TraceLogicalScope(TraceSource traceSource, string logicalName)
  {
    if (traceSource == null)
    {
      throw new ArgumentNullException("traceSource");
    }

    if (string.IsNullOrEmpty(logicalName))
    {
      throw new ArgumentNullException("logicalName");
    }

    _traceSource = traceSource;
    _logicalName = logicalName;

    _traceSource.TraceEvent(TraceEventType.Start, 0, "Starting " + _logicalName);
  }

  /// <summary>
  /// Called when the object is cleaned up, to close the scope
  /// </summary>
  public void Dispose()
  {
    _traceSource.TraceEvent(TraceEventType.Stop, 0, "Stopping " + _logicalName);
  }
}

TraceTransferScope

The TraceTransferScope class provides a simple and safe way to encapsulate a Transfer to and from an activity.

/// <summary>
/// Represents a Trace Transfer scope within which tracing Transfers to and from another Activity
/// </summary>
public class TraceTransferScope : IDisposable
{
  /// <summary>
  /// The activity ID that we stitched away from when this scope was started
  /// </summary>
  private readonly Guid _oldActivityId;

  /// <summary>
  /// The activity ID that we stitched to when this scope was started
  /// </summary>
  private readonly Guid _newActivityId;

  /// <summary>
  /// The source that we are tracing through as part of this scope
  /// </summary>
  private readonly TraceSource _traceSource;

  /// <summary>
  /// The name of the activity that this scope represents
  /// </summary>
  private readonly string _activityName;

  /// <summary>
  /// Constructor used to initialize the class
  /// </summary>
  /// <param name="traceSource">The source that we are tracing through as part of this scope</param>
  /// <param name="activityName">The name of the activity that this scope represents</param>
  public TraceTransferScope(TraceSource traceSource, string activityName)
  {
    if (traceSource == null)
    {
      throw new ArgumentNullException("traceSource");
    }

    if (string.IsNullOrEmpty(activityName))
    {
      throw new ArgumentNullException("activityName");
    }

    _traceSource = traceSource;
    _oldActivityId = Trace.CorrelationManager.ActivityId;
    _activityName = activityName;

    _newActivityId = Guid.NewGuid();

    if (_oldActivityId != Guid.Empty)
    {
      _traceSource.TraceTransfer(0, string.Format("Transferring to {0}...", _activityName), _newActivityId);
    }

    Trace.CorrelationManager.ActivityId = _newActivityId;

    _traceSource.TraceEvent(TraceEventType.Start, 0, _activityName);
  }

  /// <summary>
  /// Called when the object is cleaned up, to close the scope
  /// </summary>
  public void Dispose()
  {
    if (_oldActivityId != Guid.Empty)
    {
      _traceSource.TraceTransfer(0, string.Format("Transferring back from {0}...", _activityName),  _oldActivityId);
    }

    _traceSource.TraceEvent(TraceEventType.Stop, 0, _activityName);

    Trace.CorrelationManager.ActivityId = _oldActivityId;
  }
}

Example

The following shows the same Start/Stop example from the top of the psoting using the new TraceLogicalScope class:

TraceSource traceSource = new TraceSource("DemoApp");

using (new TraceTransferScope(traceSource, "new activity"))
{
  // Perform the new, transferred activity here and Trace will be
  // written against the new Activity automatically, and switched back to
  // the original Activity when we drop out of this scope ...
}

Conclusion

Hopefully these classes should prove invaluable if you are instrumenting your code with Trace and Activity information.

P.N.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s