/* Copyright (C) 2019 * * This file is part of the osdev components suite * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H #define OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H // std #include #include #include #include #include "compat-c++14.h" // mlogic::common #include "sharedreaderlock.h" #include "histogram.h" namespace osdev { namespace components { namespace mqtt { namespace measurement { /** * @brief This class provides the user with Entry class for putting measurements in a histogram. * @tparam TContext A tag type that is used to give the HistogramProvider a user defined context. * @tparam TValue Defines the value type that the histograms of this provider use. * @tparam Buckets The number of buckets to use on creation of a Histogram. The default number of buckets is 10. * * The TValue type must define the following publically visible members. * * value_type - The underlying value type used in the histogram * const value_type minValue - The minimum value of the histogram * const value_type maxValue - The maximum value of the histogram * const char* unit - The value unit. */ template class HistogramProvider { public: using HistogramType = Histogram; /** * @brief Get the HistogramProvider instance. */ static HistogramProvider& instance(); /** * @brief Add a value to the histogram identified by id. * @param id Identifies the histogram to add the value to. * @param value The value to add. */ void addValue(const std::string& id, typename TValue::value_type value); /** * @brief Log the histogram identified by id via the ILogger framework. * @param id The histogram to log. If no histogram is found no work is done. */ void log(const std::string& id); /** * @brief Log the histograms via the ILogger framework. * @param onlyChanged When set to true only log histograms that have changed. Default is false. */ void logAll(bool onlyChanged = false); /** * @brief Reset all the histograms. * @param logBeforeReset Flag that indicates whether the histogram needs to be logged before reset. Default is true. * @note Only changed histograms are logged. */ void resetAll(bool logBeforeReset = true); /** * @return The logOnDestroy flag value. */ bool logOnDestroy() const { return m_logOnDestroy; } /** * @brief Set the logOnDestroy flag. * @param logOnDest Log on destruction when true, do not log when set to false. */ void setLogOnDestroy(bool logOnDest) { m_logOnDestroy = logOnDest; } private: HistogramProvider(); /** * @brief On destruction the provider will log all its histogram information to stdout. * Since the destruction will happen as one of the last things in the process, stdout is * used for logging. */ ~HistogramProvider(); void log(const HistogramType& hist, bool onlyChanged); SharedReaderLock m_sharedLock; std::unordered_map> m_histograms; bool m_logOnDestroy; ///< Default is true. }; // static template HistogramProvider& HistogramProvider::instance() { static HistogramProvider s_provider; return s_provider; } template void HistogramProvider::addValue(const std::string& id, typename TValue::value_type value) { OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock); auto it = m_histograms.find(id); if (m_histograms.end() == it) { OSDEV_COMPONENTS_EXCLUSIVELOCK_SCOPE(m_sharedLock); constexpr TValue val; it = (m_histograms.emplace(std::make_pair(id, std::make_unique(id, val.minValue, val.maxValue, val.unit)))).first; } it->second->setValue(value); } template void HistogramProvider::log(const std::string& id) { OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock); auto it = m_histograms.find(id); if (m_histograms.end() != it) { log(*(it->second), false); } } template void HistogramProvider::logAll(bool onlyChanged) { OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock); for (const auto& h : m_histograms) { log(*h.second, onlyChanged); } } template void HistogramProvider::resetAll(bool logBeforeReset) { OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock); for (const auto& h : m_histograms) { if (logBeforeReset) { log(*h.second, true); // only log the histograms that have changed } h.second->reset(); } } template HistogramProvider::HistogramProvider() : m_sharedLock() , m_histograms() , m_logOnDestroy(true) { } template HistogramProvider::~HistogramProvider() { if (m_logOnDestroy) { for (const auto& h : m_histograms) { std::cout << *h.second << std::endl; } } } template void HistogramProvider::log(const HistogramType& hist, bool onlyChanged) { if ((onlyChanged && hist.isUpdated()) || !onlyChanged) { MLOGIC_COMMON_INFO("HistogramProvider", "%1", hist); } } } // End namespace measurement } // End namespace mqtt } // End namespace components } // End namespace osdev #endif // OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H