/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #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