using System; using System.ComponentModel; 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. /// public class DisposableTimer : DisposableObject { private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); private readonly Action _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"); _callback = x => { if (profiler != null) { profiler.DisposeIfDisposable(); } switch (logType) { case LogType.Debug: logger.Debug(loggerType, () => endMessage + " (took " + x + "ms)"); break; case LogType.Info: logger.Info(loggerType, () => endMessage + " (took " + x + "ms)"); break; default: throw new ArgumentOutOfRangeException("logType"); } }; 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) { profiler.Step(loggerType, startMessage); } } protected internal DisposableTimer(Action callback) { if (callback == null) throw new ArgumentNullException("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 [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use the other methods that specify strings instead of Func")] public static DisposableTimer TraceDuration(Func startMessage, Func 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 startMessage, Func completeMessage) { return new DisposableTimer( LoggerResolver.Current.Logger, LogType.Info, ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null, loggerType, startMessage(), completeMessage()); } /// /// Adds a start and end log entry as Info and tracks how long it takes until disposed. /// /// /// /// /// [Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")] public static DisposableTimer TraceDuration(string startMessage, string completeMessage) { return TraceDuration(typeof(T), startMessage, completeMessage); } /// /// Adds a start and end log entry as Info and tracks how long it takes until disposed. /// /// /// /// [Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")] 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. /// /// /// /// /// [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 /// /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. /// /// /// /// /// [Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")] public static DisposableTimer DebugDuration(string startMessage, string completeMessage) { return DebugDuration(typeof(T), startMessage, completeMessage); } /// /// Adds a start and end log entry as Debug and tracks how long it takes until disposed. /// /// /// /// [Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")] public static DisposableTimer DebugDuration(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(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. /// /// /// /// /// [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 startMessage, Func completeMessage) { return new DisposableTimer( LoggerResolver.Current.Logger, LogType.Debug, ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null, loggerType, startMessage(), completeMessage()); } #endregion /// /// Handles the disposal of resources. Derived from abstract class which handles common required locking logic. /// protected override void DisposeResources() { _callback.Invoke(Stopwatch.ElapsedMilliseconds); } } }