#include "report.hpp" #include "report_manager.hpp" #include "utils/transform.hpp" #include #include Report::Report(boost::asio::io_context& ioc, const std::shared_ptr& objServer, const std::string& reportName, const std::string& reportingTypeIn, const bool emitsReadingsUpdateIn, const bool logToMetricReportsCollectionIn, const std::chrono::milliseconds intervalIn, const ReadingParameters& readingParametersIn, interfaces::ReportManager& reportManager, interfaces::JsonStorage& reportStorageIn, std::vector> metrics) : name(reportName), path(reportDir + name), reportingType(reportingTypeIn), interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn), logToMetricReportsCollection(logToMetricReportsCollectionIn), readingParameters(readingParametersIn), objServer(objServer), metrics(std::move(metrics)), timer(ioc), fileName(std::to_string(std::hash{}(name))), reportStorage(reportStorageIn) { for (auto& metric : this->metrics) { metric->initialize(); } deleteIface = objServer->add_unique_interface( path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) { dbusIface.register_method("Delete", [this, &ioc, &reportManager] { if (persistency) { reportStorage.remove(fileName); } boost::asio::post(ioc, [this, &reportManager] { reportManager.removeReport(this); }); }); }); reportIface = objServer->add_unique_interface( path, reportIfaceName, [this](auto& dbusIface) { dbusIface.register_property_rw( "Interval", static_cast(interval.count()), sdbusplus::vtable::property_::emits_change, [this](uint64_t newVal, auto&) { std::chrono::milliseconds newValT(newVal); if (newValT < ReportManager::minInterval) { return false; } interval = newValT; return true; }, [this](const auto&) { return static_cast(interval.count()); }); persistency = storeConfiguration(); dbusIface.register_property_rw( "Persistency", persistency, sdbusplus::vtable::property_::emits_change, [this](bool newVal, const auto&) { if (newVal == persistency) { return true; } if (newVal) { persistency = storeConfiguration(); } else { reportStorage.remove(fileName); persistency = false; } return true; }, [this](const auto&) { return persistency; }); dbusIface.register_property_r( "Readings", readings, sdbusplus::vtable::property_::emits_change, [this](const auto&) { return readings; }); dbusIface.register_property_r( "ReportingType", reportingType, sdbusplus::vtable::property_::const_, [this](const auto&) { return reportingType; }); dbusIface.register_property_r( "ReadingParameters", readingParameters, sdbusplus::vtable::property_::const_, [this](const auto&) { return readingParameters; }); dbusIface.register_property_r( "EmitsReadingsUpdate", emitsReadingsUpdate, sdbusplus::vtable::property_::const_, [this](const auto&) { return emitsReadingsUpdate; }); dbusIface.register_property_r( "LogToMetricReportsCollection", logToMetricReportsCollection, sdbusplus::vtable::property_::const_, [this](const auto&) { return logToMetricReportsCollection; }); dbusIface.register_method("Update", [this] { if (reportingType == "OnRequest") { updateReadings(); } }); }); if (reportingType == "Periodic") { scheduleTimer(interval); } } void Report::timerProc(boost::system::error_code ec, Report& self) { if (ec) { return; } self.updateReadings(); self.scheduleTimer(self.interval); } void Report::scheduleTimer(std::chrono::milliseconds timerInterval) { timer.expires_after(timerInterval); timer.async_wait( [this](boost::system::error_code ec) { timerProc(ec, *this); }); } void Report::updateReadings() { auto numElements = std::accumulate( metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) { return sum + metric->getReadings().size(); }); std::tuple_element_t<1, Readings> readingsCache(numElements); auto it = readingsCache.begin(); for (const auto& metric : metrics) { for (const auto& reading : metric->getReadings()) { *(it++) = std::make_tuple(reading.id, reading.metadata, reading.value, reading.timestamp); } } std::get<0>(readings) = std::time(0); std::get<1>(readings) = std::move(readingsCache); reportIface->signal_property("Readings"); } bool Report::storeConfiguration() const { try { nlohmann::json data; data["Version"] = reportVersion; data["Name"] = name; data["ReportingType"] = reportingType; data["EmitsReadingsUpdate"] = emitsReadingsUpdate; data["LogToMetricReportsCollection"] = logToMetricReportsCollection; data["Interval"] = interval.count(); data["ReadingParameters"] = utils::transform( metrics, [](const auto& metric) { return metric->to_json(); }); reportStorage.store(fileName, data); } catch (const std::exception& e) { phosphor::logging::log( "Failed to store a report in storage", phosphor::logging::entry("msg=", e.what())); return false; } return true; }