2012-07-28 23:08:02 +06:00
using System ;
using System.Diagnostics ;
2013-05-14 13:39:55 -10:00
using System.Web ;
2012-07-28 23:08:02 +06:00
using Umbraco.Core.Logging ;
2013-05-13 21:11:03 -10:00
using Umbraco.Core.Profiling ;
2012-07-28 23:08:02 +06:00
namespace Umbraco.Core
{
/// <summary>
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
/// </summary>
/// <example>
/// <code>
2013-05-13 21:11:03 -10:00
///
/// using (DisposableTimer.TraceDuration{MyType}("starting", "finished"))
/// {
/// Thread.Sleep(567);
/// }
///
2012-07-28 23:08:02 +06:00
/// Console.WriteLine("Testing Stopwatchdisposable, should be 567:");
2013-05-13 21:11:03 -10:00
/// using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result)))
/// {
/// Thread.Sleep(567);
/// }
2012-07-28 23:08:02 +06:00
/// </code>
/// </example>
public class DisposableTimer : DisposableObject
{
private readonly Stopwatch _stopwatch = Stopwatch . StartNew ( ) ;
private readonly Action < long > _callback ;
protected DisposableTimer ( Action < long > callback )
{
_callback = callback ;
2013-05-14 13:39:55 -10:00
}
2013-05-13 21:11:03 -10:00
2012-07-28 23:08:02 +06:00
public Stopwatch Stopwatch
{
get { return _stopwatch ; }
}
/// <summary>
/// Starts the timer and invokes the specified callback upon disposal.
/// </summary>
/// <param name="callback">The callback.</param>
/// <returns></returns>
2013-05-14 13:39:55 -10:00
[Obsolete("Use either TraceDuration or DebugDuration instead of using Start")]
2012-07-28 23:08:02 +06:00
public static DisposableTimer Start ( Action < long > callback )
{
return new DisposableTimer ( callback ) ;
}
2013-05-13 21:11:03 -10:00
#region TraceDuration
public static DisposableTimer TraceDuration < T > ( Func < string > startMessage , Func < string > completeMessage )
{
return TraceDuration ( typeof ( T ) , startMessage , completeMessage ) ;
}
2012-11-27 10:42:22 +05:00
2013-05-13 21:11:03 -10:00
public static DisposableTimer TraceDuration ( Type loggerType , Func < string > startMessage , Func < string > completeMessage )
{
2013-05-14 13:39:55 -10:00
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 ) ;
} ) ;
2013-05-13 21:11:03 -10:00
}
2012-07-28 23:08:02 +06:00
2013-05-13 21:11:03 -10:00
/// <summary>
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer TraceDuration < T > ( string startMessage , string completeMessage )
{
return TraceDuration ( typeof ( T ) , startMessage , completeMessage ) ;
}
2012-07-28 23:08:02 +06:00
2013-05-13 22:13:52 -10:00
public static DisposableTimer TraceDuration < T > ( string startMessage )
{
return TraceDuration ( typeof ( T ) , startMessage , "Complete" ) ;
}
2013-05-13 21:11:03 -10:00
/// <summary>
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
/// </summary>
/// <param name="loggerType"></param>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer TraceDuration ( Type loggerType , string startMessage , string completeMessage )
{
2013-05-14 13:39:55 -10:00
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 ) ;
} ) ;
2013-05-13 21:11:03 -10:00
}
#endregion
2012-07-30 22:52:59 +06:00
2013-05-13 21:11:03 -10:00
#region DebugDuration
/// <summary>
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer DebugDuration < T > ( string startMessage , string completeMessage )
{
return DebugDuration ( typeof ( T ) , startMessage , completeMessage ) ;
}
2012-11-20 08:34:32 -01:00
2013-05-13 22:13:52 -10:00
public static DisposableTimer DebugDuration < T > ( string startMessage )
{
return DebugDuration ( typeof ( T ) , startMessage , "Complete" ) ;
}
2013-05-13 21:11:03 -10:00
/// <summary>
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer DebugDuration < T > ( Func < string > startMessage , Func < string > completeMessage )
{
return DebugDuration ( typeof ( T ) , startMessage , completeMessage ) ;
}
2012-07-30 22:52:59 +06:00
2013-05-13 21:11:03 -10:00
/// <summary>
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
/// </summary>
/// <param name="loggerType"></param>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer DebugDuration ( Type loggerType , string startMessage , string completeMessage )
{
2013-05-14 13:39:55 -10:00
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 ) ;
} ) ;
2013-05-13 21:11:03 -10:00
}
/// <summary>
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
/// </summary>
/// <param name="loggerType"></param>
/// <param name="startMessage"></param>
/// <param name="completeMessage"></param>
/// <returns></returns>
public static DisposableTimer DebugDuration ( Type loggerType , Func < string > startMessage , Func < string > completeMessage )
{
var msg = startMessage ( ) ;
LogHelper . Debug ( loggerType , msg ) ;
2013-05-14 13:39:55 -10:00
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 ) ;
} ) ;
2013-05-13 21:11:03 -10:00
}
#endregion
2012-11-20 08:34:32 -01:00
2012-07-28 23:08:02 +06:00
/// <summary>
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
/// </summary>
protected override void DisposeResources ( )
{
_callback . Invoke ( Stopwatch . ElapsedMilliseconds ) ;
}
2013-05-14 13:39:55 -10:00
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 ;
}
2012-07-28 23:08:02 +06:00
}
}