#pragma once #include "metric.h" #include #include namespace NMonitoring { /** * A timing scope to record elapsed time since creation. */ template class TMetricTimerScope { public: explicit TMetricTimerScope(TMetric* metric) : Metric_(metric) , StartTime_(Clock::now()) { Y_ENSURE(Metric_); } TMetricTimerScope(TMetricTimerScope&) = delete; TMetricTimerScope& operator=(const TMetricTimerScope&) = delete; TMetricTimerScope(TMetricTimerScope&& other) { *this = std::move(other); } TMetricTimerScope& operator=(TMetricTimerScope&& other) { Metric_ = other.Metric_; other.Metric_ = nullptr; StartTime_ = std::move(other.StartTime_); return *this; } void Record() { Y_DEBUG_ABORT_UNLESS(Metric_); if (Metric_ == nullptr) { return; } auto duration = std::chrono::duration_cast(Clock::now() - StartTime_).count(); if constexpr (std::is_same::value) { Metric_->Set(duration); } else if constexpr (std::is_same::value) { Metric_->Set(duration); } else if constexpr (std::is_same::value) { Metric_->Add(duration); } else if constexpr (std::is_same::value) { Metric_->Add(duration); } else if constexpr (std::is_same::value) { Metric_->Record(duration); } else { static_assert(TDependentFalse, "Not supported metric type"); } Metric_ = nullptr; } ~TMetricTimerScope() { if (Metric_ == nullptr) { return; } Record(); } private: TMetric* Metric_{nullptr}; typename Clock::time_point StartTime_; }; /** * @brief A class that is supposed to use to measure execution time of an asynchronuous operation. * * In order to be able to capture an object into a lambda which is then passed to TFuture::Subscribe/Apply, * the object must be copy constructible (limitation of the std::function class). So, we cannot use the TMetricTimerScope * with the abovementioned functions without storing it in a shared pointer or somewhere else. This class works around this * issue with wrapping the timer with a auto_ptr-like hack Also, Record is const so that one doesn't need to make every lambda mutable * just to record time measurement. */ template class TFutureFriendlyTimer { public: explicit TFutureFriendlyTimer(TMetric* metric) : Impl_{metric} { } TFutureFriendlyTimer(const TFutureFriendlyTimer& other) : Impl_{std::move(other.Impl_)} { } TFutureFriendlyTimer& operator=(const TFutureFriendlyTimer& other) { Impl_ = std::move(other.Impl_); } TFutureFriendlyTimer(TFutureFriendlyTimer&&) = default; TFutureFriendlyTimer& operator=(TFutureFriendlyTimer&& other) = default; void Record() const { Impl_.Record(); } private: mutable TMetricTimerScope Impl_; }; template TMetricTimerScope ScopeTimer(TMetric* metric) { return TMetricTimerScope{metric}; } template TFutureFriendlyTimer FutureTimer(TMetric* metric) { return TFutureFriendlyTimer{metric}; } }