using System;
using System.Diagnostics;
using System.Web;
using Umbraco.Core.Logging;
using Umbraco.Core.Profiling;
namespace Umbraco.Core
{
///
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a using (C#) statement.
///
///
///
///
/// using (DisposableTimer.TraceDuration{MyType}("starting", "finished"))
/// {
/// Thread.Sleep(567);
/// }
///
/// Console.WriteLine("Testing Stopwatchdisposable, should be 567:");
/// using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result)))
/// {
/// Thread.Sleep(567);
/// }
///
///
public class DisposableTimer : DisposableObject
{
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private readonly Action _callback;
protected DisposableTimer(Action callback)
{
_callback = callback;
}
public Stopwatch Stopwatch
{
get { return _stopwatch; }
}
///
/// Starts the timer and invokes the specified callback upon disposal.
///
/// The callback.
///
[Obsolete("Use either TraceDuration or DebugDuration instead of using Start")]
public static DisposableTimer Start(Action callback)
{
return new DisposableTimer(callback);
}
#region TraceDuration
public static DisposableTimer TraceDuration(Func startMessage, Func completeMessage)
{
return TraceDuration(typeof(T), startMessage, completeMessage);
}
public static DisposableTimer TraceDuration(Type loggerType, Func startMessage, Func completeMessage)
{
var startMsg = startMessage();
LogHelper.Info(loggerType, startMsg);
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("Start: " + startMsg);
var profiler = ActivateProfiler(loggerType, startMsg);
return new DisposableTimer(x =>
{
profiler.DisposeIfDisposable();
LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)");
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("End: " + startMsg);
});
}
///
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer TraceDuration(string startMessage, string completeMessage)
{
return TraceDuration(typeof(T), startMessage, completeMessage);
}
public static DisposableTimer TraceDuration(string startMessage)
{
return TraceDuration(typeof(T), startMessage, "Complete");
}
///
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
{
LogHelper.Info(loggerType, startMessage);
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("Start: " + startMessage);
var profiler = ActivateProfiler(loggerType, startMessage);
return new DisposableTimer(x =>
{
profiler.DisposeIfDisposable();
LogHelper.Info(loggerType, () => completeMessage + " (took " + x + "ms)");
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("End: " + startMessage);
});
}
#endregion
#region DebugDuration
///
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer DebugDuration(string startMessage, string completeMessage)
{
return DebugDuration(typeof(T), startMessage, completeMessage);
}
public static DisposableTimer DebugDuration(string startMessage)
{
return DebugDuration(typeof(T), startMessage, "Complete");
}
///
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer DebugDuration(Func startMessage, Func completeMessage)
{
return DebugDuration(typeof(T), startMessage, completeMessage);
}
///
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
{
LogHelper.Debug(loggerType, startMessage);
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("Start: " + startMessage);
var profiler = ActivateProfiler(loggerType, startMessage);
return new DisposableTimer(x =>
{
profiler.DisposeIfDisposable();
LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)");
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("End: " + startMessage);
});
}
///
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
///
///
///
///
///
public static DisposableTimer DebugDuration(Type loggerType, Func startMessage, Func completeMessage)
{
var msg = startMessage();
LogHelper.Debug(loggerType, msg);
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("Start: " + startMessage);
var profiler = ActivateProfiler(loggerType, msg);
return new DisposableTimer(x =>
{
profiler.DisposeIfDisposable();
LogHelper.Debug(loggerType, () => completeMessage() + " (took " + x + "ms)");
if (HttpContext.Current != null)
HttpContext.Current.Trace.Write("End: " + startMessage);
});
}
#endregion
///
/// Handles the disposal of resources. Derived from abstract class which handles common required locking logic.
///
protected override void DisposeResources()
{
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
}
private static IDisposable ActivateProfiler(Type loggerType, string profileName)
{
try
{
return ProfilerResolver.Current.Profiler.Step(loggerType, profileName);
}
catch (InvalidOperationException)
{
//swallow this exception, it will occur if the ProfilerResolver is not initialized... generally only in
// unit tests.
}
return null;
}
}
}