Click here to Skip to main content
15,892,575 members
Articles / Desktop Programming / XAML

Diagnostic Explorer

Rate me:
Please Sign up or sign in to vote.
4.93/5 (41 votes)
29 Nov 2010LGPL315 min read 82.6K   1.5K   120  
A .NET library and website which allows developers to expose and view arbitrary diagnostic information about their .NET processes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace DiagnosticExplorer.Silverlight
{
	public static class TraceParser
	{
		private static Regex itemRegex = new Regex(@"\[([0-9]+\.[0-9]+)\] \[([0-9]+\.[0-9]+)\]( (BEGIN|END|BEGIN/END))? (.*)");
		private static Regex secondsRegex = new Regex(@" \(([0-9]+\.[0-9]+) seconds\)?");

		public static TraceItem Parse(string text)
		{
			try
			{
				TraceParent parent = ParseFromText(text);
				if (parent != null)
				{
					foreach (TraceItem child in parent.Children)
						PopulateInterest(child, parent.Total);
					parent.Expanded = true;
				}

				return parent;
			}
			catch (Exception ex)
			{
				TraceParent error = new TraceParent();
				error.Text = ex.Message;
				error.Detail = ex.ToString();
				return error;
			}
		}

		private static void PopulateInterest(TraceItem item, TimeSpan total)
		{
			TraceParent parent = item as TraceParent;
			if (parent != null)
			{
				foreach (TraceItem child in parent.Children)
					PopulateInterest(child, total);

				parent.InterestLevel = GetInterestLevel(parent.Total, total);
				parent.Expanded = parent.Children.Any(x => x.InterestLevel == InterestLevel.High);
			}
			else
			{
				item.InterestLevel = GetInterestLevel(item.TimeDelta, total);
			}
		}

		private static InterestLevel GetInterestLevel(TimeSpan delta, TimeSpan total)
		{
			if (total.TotalMilliseconds == 0) return InterestLevel.Low;

			double timePercentage = delta.TotalMilliseconds / total.TotalMilliseconds * 100;
			if (timePercentage > 10) return InterestLevel.High;
			if (timePercentage > 5) return InterestLevel.Medium;
			return InterestLevel.Low;
		}

		public static TraceParent ParseFromText(string text)
		{
			if (string.IsNullOrEmpty(text))
				return null;

			Match firstMatch = itemRegex.Match(text);
			if (!firstMatch.Success)
				return null;

			text = text.Substring(firstMatch.Index);

			string[] lines = Regex.Split(text, Environment.NewLine);
			Stack<TraceParent> stack = new Stack<TraceParent>();

			foreach (string line in lines)
			{
				Match match = itemRegex.Match(line);
				if (!match.Success)
				{
					TraceItem item = stack.Peek().Children.Last();
					if (item.Detail != null)
						item.Detail += Environment.NewLine;

					string pattern = string.Format("^ {{1,{0}}}", stack.Count * 4 + 14);
					item.Detail += Regex.Replace(line, pattern, "");
					continue;
				}

				string rawText = match.Groups[5].Value;
				string itemText = secondsRegex.Replace(rawText, "");
				TimeSpan time1 = TimeSpan.FromSeconds(double.Parse(match.Groups[1].Value));
				TimeSpan time2 = TimeSpan.FromSeconds(double.Parse(match.Groups[2].Value));

				string type = match.Groups[4].Value;
				switch (type)
				{
					case "BEGIN":
						{

							TraceParent newParent = new TraceParent();
							newParent.TimeTotal = time1;
							newParent.TimeDelta = time2;
							newParent.Text = itemText;
							Match secondsMatch = secondsRegex.Match(rawText);
							if (secondsMatch.Success)
							{
								double seconds = double.Parse(secondsMatch.Groups[1].Value);
								newParent.EndTimeTotal = newParent.TimeTotal + TimeSpan.FromSeconds(seconds);
							}

							if (stack.Count != 0)
								stack.Peek().Children.Add(newParent);
							stack.Push(newParent);
							break;
						}
					case "END":
						{
							TraceParent parent = stack.Pop();
//							parent.EndTimeTotal = time1;
							parent.EndTimeDelta = time2;

							TraceItem item = new TraceItem();
							item.TimeTotal = time1;
							item.TimeDelta = time2;
							item.Text = "End";
							parent.Children.Add(item);

							if (stack.Count == 0)
								return parent;
							break;
						}
					case "":
					case "BEGIN/END":
						{
							TraceItem item = new TraceItem();
							item.TimeTotal = time1;
							item.TimeDelta = time2;
							item.Text = itemText;
							stack.Peek().Children.Add(item);
							break;
						}
				}
			}
			if (stack.Count == 0)
				return null;

			TraceParent result = stack.Pop();
			while (stack.Count != 0)
				result = stack.Pop();

			return result;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer
United Kingdom United Kingdom
I am a software developer originally from Auckland, New Zealand. I have lived and worked in London since 2005.

Comments and Discussions