Files
Umbraco-CMS/src/Umbraco.Core/DisposableTimer.cs

253 lines
9.8 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Web;
using Umbraco.Core.Logging;
using Umbraco.Core.Profiling;
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>
public class DisposableTimer : DisposableObject
{
private readonly ILogger _logger;
private readonly LogType? _logType;
private readonly IProfiler _profiler;
private readonly Type _loggerType;
private readonly string _endMessage;
private readonly IDisposable _profilerStep;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private readonly Action<long> _callback;
internal enum LogType
{
Debug, Info
}
internal DisposableTimer(ILogger logger, LogType logType, IProfiler profiler, Type loggerType, string startMessage, string endMessage)
{
if (logger == null) throw new ArgumentNullException("logger");
if (loggerType == null) throw new ArgumentNullException("loggerType");
_logger = logger;
_logType = logType;
_profiler = profiler;
_loggerType = loggerType;
_endMessage = endMessage;
switch (logType)
{
case LogType.Debug:
logger.Debug(loggerType, startMessage);
break;
case LogType.Info:
logger.Info(loggerType, startMessage);
break;
default:
throw new ArgumentOutOfRangeException("logType");
}
if (profiler != null)
{
_profilerStep = profiler.Step(loggerType, startMessage);
}
}
protected internal DisposableTimer(Action<long> callback)
{
if (callback == null) throw new ArgumentNullException("callback");
_callback = callback;
}
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>
[Obsolete("Use either TraceDuration or DebugDuration instead of using Start")]
public static DisposableTimer Start(Action<long> callback)
{
return new DisposableTimer(callback);
}
#region TraceDuration
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the other methods that specify strings instead of Func")]
public static DisposableTimer TraceDuration<T>(Func<string> startMessage, Func<string> completeMessage)
{
return TraceDuration(typeof(T), startMessage, completeMessage);
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the other methods that specify strings instead of Func")]
public static DisposableTimer TraceDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
{
return new DisposableTimer(
LoggerResolver.Current.Logger,
LogType.Info,
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
loggerType,
startMessage(),
completeMessage());
}
/// <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>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer TraceDuration<T>(string startMessage, string completeMessage)
{
return TraceDuration(typeof(T), startMessage, completeMessage);
}
/// <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>
/// <returns></returns>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer TraceDuration<T>(string startMessage)
{
return TraceDuration(typeof(T), startMessage, "Complete");
}
/// <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>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
{
return new DisposableTimer(
LoggerResolver.Current.Logger,
LogType.Info,
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
loggerType,
startMessage,
completeMessage);
}
#endregion
#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>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer DebugDuration<T>(string startMessage, string completeMessage)
{
return DebugDuration(typeof(T), startMessage, completeMessage);
}
/// <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>
/// <returns></returns>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer DebugDuration<T>(string startMessage)
{
return DebugDuration(typeof(T), startMessage, "Complete");
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the other methods that specify strings instead of Func")]
public static DisposableTimer DebugDuration<T>(Func<string> startMessage, Func<string> completeMessage)
{
return DebugDuration(typeof(T), startMessage, completeMessage);
}
/// <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>
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
{
return new DisposableTimer(
LoggerResolver.Current.Logger,
LogType.Debug,
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
loggerType,
startMessage,
completeMessage);
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the other methods that specify strings instead of Func")]
public static DisposableTimer DebugDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
{
return new DisposableTimer(
LoggerResolver.Current.Logger,
LogType.Debug,
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
loggerType,
startMessage(),
completeMessage());
}
#endregion
/// <summary>
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
/// </summary>
protected override void DisposeResources()
{
if (_profiler != null)
{
_profiler.DisposeIfDisposable();
}
if (_profilerStep != null)
{
_profilerStep.Dispose();
}
if (_logType.HasValue && _endMessage.IsNullOrWhiteSpace() == false && _loggerType != null && _logger != null)
{
switch (_logType)
{
case LogType.Debug:
_logger.Debug(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
break;
case LogType.Info:
_logger.Info(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
break;
default:
throw new ArgumentOutOfRangeException("logType");
}
}
if (_callback != null)
{
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
}
}
}
}