#pragma once #include "util/prometheus/Counter.hpp" #include "util/prometheus/Gauge.hpp" #include "util/prometheus/Histogram.hpp" #include #include #include #include #include #include namespace data { /** * @brief A concept for a class that can be used to count backend operations. */ template concept SomeBackendCounters = requires(T a) { typename T::PtrType; { a.registerTooBusy() } -> std::same_as; { a.registerWriteSync(std::chrono::steady_clock::time_point{}) } -> std::same_as; { a.registerWriteSyncRetry() } -> std::same_as; { a.registerWriteStarted() } -> std::same_as; { a.registerWriteFinished(std::chrono::steady_clock::time_point{}) } -> std::same_as; { a.registerWriteRetry() } -> std::same_as; { a.registerReadStarted(std::uint64_t{}) } -> std::same_as; { a.registerReadFinished(std::chrono::steady_clock::time_point{}, std::uint64_t{}) } -> std::same_as; { a.registerReadRetry(std::uint64_t{}) } -> std::same_as; { a.registerReadError(std::uint64_t{}) } -> std::same_as; { a.report() } -> std::same_as; }; /** * @brief Holds statistics about the backend. * * @note This class is thread-safe. */ class BackendCounters { public: using PtrType = std::shared_ptr; /** * @brief Create a new BackendCounters object * * @return A shared pointer to the new BackendCounters object */ static PtrType make(); /** * @brief Register that the backend was too busy to process a request */ void registerTooBusy(); /** * @brief Register that a write operation was started * * @param startTime The time the operation was started */ void registerWriteSync(std::chrono::steady_clock::time_point startTime); /** * @brief Register that a write operation was retried */ void registerWriteSyncRetry(); /** * @brief Register that a write operation was started */ void registerWriteStarted(); /** * @brief Register that a write operation was finished * * @param startTime The time the operation was started */ void registerWriteFinished(std::chrono::steady_clock::time_point startTime); /** * @brief Register that a write operation was retried */ void registerWriteRetry(); /** * @brief Register that one or more read operations were started * * @param count The number of operations started */ void registerReadStarted(std::uint64_t count = 1u); /** * @brief Register that one or more read operations were finished * * @param startTime The time the operations were started * @param count The number of operations finished */ void registerReadFinished(std::chrono::steady_clock::time_point startTime, std::uint64_t count = 1u); /** * @brief Register that one or more read operations were retried * * @param count The number of operations retried */ void registerReadRetry(std::uint64_t count = 1u); /** * @brief Register that one or more read operations had an error * * @param count The number of operations with an error */ void registerReadError(std::uint64_t count = 1u); /** * @brief Get a report of the backend counters * * @return The report */ [[nodiscard]] boost::json::object report() const; private: BackendCounters(); class AsyncOperationCounters { public: AsyncOperationCounters(std::string name); void registerStarted(std::uint64_t count); void registerFinished(std::uint64_t count); void registerRetry(std::uint64_t count); void registerError(std::uint64_t count); [[nodiscard]] boost::json::object report() const; private: std::string name_; std::reference_wrapper pendingCounter_; std::reference_wrapper completedCounter_; std::reference_wrapper retryCounter_; std::reference_wrapper errorCounter_; }; std::reference_wrapper tooBusyCounter_; std::reference_wrapper writeSyncCounter_; std::reference_wrapper writeSyncRetryCounter_; AsyncOperationCounters asyncWriteCounters_{"write_async"}; AsyncOperationCounters asyncReadCounters_{"read_async"}; std::reference_wrapper readDurationHistogram_; std::reference_wrapper writeDurationHistogram_; }; } // namespace data