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 { /// /// 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 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 _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 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() { 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); } } } }