#include "metrics/collection_function.hpp" #include namespace metrics { class FunctionMinimum : public CollectionFunction { public: double calculate(const std::vector& readings, Milliseconds) const override { return std::min_element( readings.begin(), readings.end(), [](const auto& left, const auto& right) { return std::make_tuple(!std::isfinite(left.second), left.second) < std::make_tuple(!std::isfinite(right.second), right.second); }) ->second; } double calculateForStartupInterval(std::vector& readings, Milliseconds timestamp) const override { readings.assign( {ReadingItem(timestamp, calculate(readings, timestamp))}); return readings.back().second; } }; class FunctionMaximum : public CollectionFunction { public: double calculate(const std::vector& readings, Milliseconds) const override { return std::max_element( readings.begin(), readings.end(), [](const auto& left, const auto& right) { return std::make_tuple(std::isfinite(left.second), left.second) < std::make_tuple(std::isfinite(right.second), right.second); }) ->second; } double calculateForStartupInterval(std::vector& readings, Milliseconds timestamp) const override { readings.assign( {ReadingItem(timestamp, calculate(readings, timestamp))}); return readings.back().second; } }; class FunctionAverage : public CollectionFunction { public: double calculate(const std::vector& readings, Milliseconds timestamp) const override { auto valueSum = 0.0; auto timeSum = Milliseconds{0}; for (auto it = readings.begin(); it != std::prev(readings.end()); ++it) { if (std::isfinite(it->second)) { const auto kt = std::next(it); const auto duration = kt->first - it->first; valueSum += it->second * duration.count(); timeSum += duration; } } const auto duration = timestamp - readings.back().first; valueSum += readings.back().second * duration.count(); timeSum += duration; return valueSum / std::max(timeSum.count(), uint64_t{1u}); } double calculateForStartupInterval(std::vector& readings, Milliseconds timestamp) const override { auto result = calculate(readings, timestamp); if (std::isfinite(result)) { readings.assign({ReadingItem(readings.front().first, result), ReadingItem(timestamp, readings.back().second)}); } return result; } }; class FunctionSummation : public CollectionFunction { using Multiplier = std::chrono::duration; public: double calculate(const std::vector& readings, const Milliseconds timestamp) const override { auto valueSum = 0.0; for (auto it = readings.begin(); it != std::prev(readings.end()); ++it) { if (std::isfinite(it->second)) { const auto kt = std::next(it); const auto multiplier = calculateMultiplier(kt->first - it->first); valueSum += it->second * multiplier.count(); } } const auto multiplier = calculateMultiplier(timestamp - readings.back().first); valueSum += readings.back().second * multiplier.count(); return valueSum; } double calculateForStartupInterval(std::vector& readings, const Milliseconds timestamp) const override { const auto result = calculate(readings, timestamp); if (readings.size() > 2 && std::isfinite(result)) { const auto multiplier = calculateMultiplier(timestamp - readings.front().first).count(); if (multiplier > 0.) { const auto prevValue = result / multiplier; readings.assign( {ReadingItem(readings.front().first, prevValue), ReadingItem(timestamp, readings.back().second)}); } } return result; } private: static constexpr Multiplier calculateMultiplier(Milliseconds duration) { constexpr auto m = Multiplier{Seconds{1}}; return Multiplier{duration / m}; } }; std::shared_ptr makeCollectionFunction(OperationType operationType) { using namespace std::string_literals; switch (operationType) { case OperationType::min: return std::make_shared(); case OperationType::max: return std::make_shared(); case OperationType::avg: return std::make_shared(); case OperationType::sum: return std::make_shared(); default: throw std::runtime_error("op: "s + utils::enumToString(operationType) + " is not supported"s); } } } // namespace metrics