Skip to content

Instantly share code, notes, and snippets.

@rebornix
Created July 25, 2012 06:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rebornix/3174719 to your computer and use it in GitHub Desktop.
Save rebornix/3174719 to your computer and use it in GitHub Desktop.
A Performance Trace Tool
using System;
using System.Diagnostics;
using System.Text;
namespace Common
{
/// <summary>
/// This class will take down the steps in the api flow, and trace it if the latency is larger than config.
/// </summary>
public static class PerfTracer
{
[ThreadStatic]
private static StringBuilder _sb;
[ThreadStatic]
private static Stopwatch _stopwatch;
[ThreadStatic]
private static bool _inited;
[ThreadStatic]
private static int _threshold;
private static Stopwatch GetStopwatch()
{
if (_stopwatch == null)
{
_stopwatch = new Stopwatch();
}
return _stopwatch;
}
private static StringBuilder GetStringBuilder()
{
if (_sb == null)
{
_sb = new StringBuilder();
}
return _sb;
}
public static void Init(int threshold)
{
_sb = new StringBuilder();
_stopwatch = Stopwatch.StartNew();
_inited = true;
_threshold = threshold;
}
public static long GetElapsedMillisecond()
{
if (_inited)
{
return _stopwatch.ElapsedMilliseconds;
}
return 0;
}
public static void TraceStep(string stepMessage)
{
//TODO: Override this function call by replacing "DateTime.UtcNow()" to whatever u need.
TraceStep(stepMessage, DataTime.UtcNow());
}
public static void TraceStep(string stepMessage, DateTime dateTime)
{
// If not inited, means it comes from the api that is not enabled with perf trace
// Then skip to avoid StringBuilder eating memory
if (_inited)
{
stepMessage = stepMessage.Replace("\r", string.Empty).Replace("\n", string.Empty);
// use '|' because the new line cannot go into tako, to get a good view, replace '|' with \r\n manually
GetStringBuilder().Append(String.Format("{0} : {1} |", dateTime.ToString("HH:mm:ss.fff"), stepMessage));
}
}
public static void Flush(string apiName, Guid trackingGuid, string partnerName)
{
var stopwatch = GetStopwatch();
stopwatch.Stop();
long latency = stopwatch.ElapsedMilliseconds;
// if exceeds the threshold, trace as Warning, otherwise Verbose
// only Warning trace would go into Tako
TraceLevel level = latency > _threshold ? TraceLevel.Warning : TraceLevel.Verbose;
Trace(level, partnerName, apiName, latency, trackingGuid);
_inited = false;
}
private static void Trace(TraceLevel level, string partnerName, string apiName, long latency, Guid trackingGuid)
{
var call = Tracer.StartTracing(new TracerTag("CommerceTransactionAPIPerfTracer"), level);
if (call != null)
{
call.Add(new TracerField("partnername"), partnerName);
call.Add(new TracerField("apiname"), apiName);
call.Add(new TracerField("latency"), latency);
call.Add(new TracerField("trackingguid"), trackingGuid.ToString());
call.Add(new TracerField("perfinfo"), GetStringBuilder().ToString());
call.Trace(String.Format("PerfTrace with threshold = {0}, for apiName = {1}, trackingGuid = {2}.",
_threshold, apiName, trackingGuid.ToString()));
}
}
}
/// <summary>
/// Wrapper of PerfTracer, to provide 'using' pattern
/// </summary>
public class PerfTraceScope : IDisposable
{
private string _step;
private long _startPoint;
public PerfTraceScope(string step)
{
_step = step;
_startPoint = PerfTracer.GetElapsedMillisecond();
PerfTracer.TraceStep(String.Format("st {0}", step));
}
public void Dispose()
{
long latency = PerfTracer.GetElapsedMillisecond() - _startPoint;
PerfTracer.TraceStep(String.Format("ed {0} - L:{1}", _step, latency));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment