1 #include "report.hpp" 2 3 #include "report_manager.hpp" 4 #include "utils/transform.hpp" 5 6 #include <phosphor-logging/log.hpp> 7 8 #include <numeric> 9 10 Report::Report(boost::asio::io_context& ioc, 11 const std::shared_ptr<sdbusplus::asio::object_server>& objServer, 12 const std::string& reportName, 13 const std::string& reportingTypeIn, 14 const bool emitsReadingsUpdateIn, 15 const bool logToMetricReportsCollectionIn, 16 const std::chrono::milliseconds intervalIn, 17 const ReadingParameters& readingParametersIn, 18 interfaces::ReportManager& reportManager, 19 interfaces::JsonStorage& reportStorageIn, 20 std::vector<std::shared_ptr<interfaces::Metric>> metrics) : 21 name(reportName), 22 path(reportDir + name), reportingType(reportingTypeIn), 23 interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn), 24 logToMetricReportsCollection(logToMetricReportsCollectionIn), 25 readingParameters(readingParametersIn), objServer(objServer), 26 metrics(std::move(metrics)), timer(ioc), 27 fileName(std::to_string(std::hash<std::string>{}(name))), 28 reportStorage(reportStorageIn) 29 { 30 deleteIface = objServer->add_unique_interface( 31 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) { 32 dbusIface.register_method("Delete", [this, &ioc, &reportManager] { 33 if (persistency) 34 { 35 reportStorage.remove(fileName); 36 } 37 boost::asio::post(ioc, [this, &reportManager] { 38 reportManager.removeReport(this); 39 }); 40 }); 41 }); 42 43 reportIface = objServer->add_unique_interface( 44 path, reportIfaceName, [this](auto& dbusIface) { 45 dbusIface.register_property_rw( 46 "Interval", static_cast<uint64_t>(interval.count()), 47 sdbusplus::vtable::property_::emits_change, 48 [this](uint64_t newVal, auto&) { 49 std::chrono::milliseconds newValT(newVal); 50 if (newValT < ReportManager::minInterval) 51 { 52 return false; 53 } 54 interval = newValT; 55 return true; 56 }, 57 [this](const auto&) { 58 return static_cast<uint64_t>(interval.count()); 59 }); 60 persistency = storeConfiguration(); 61 dbusIface.register_property_rw( 62 "Persistency", persistency, 63 sdbusplus::vtable::property_::emits_change, 64 [this](bool newVal, const auto&) { 65 if (newVal == persistency) 66 { 67 return true; 68 } 69 if (newVal) 70 { 71 persistency = storeConfiguration(); 72 } 73 else 74 { 75 reportStorage.remove(fileName); 76 persistency = false; 77 } 78 return true; 79 }, 80 [this](const auto&) { return persistency; }); 81 dbusIface.register_property_r( 82 "Readings", readings, 83 sdbusplus::vtable::property_::emits_change, 84 [this](const auto&) { return readings; }); 85 dbusIface.register_property_r( 86 "ReportingType", reportingType, 87 sdbusplus::vtable::property_::const_, 88 [this](const auto&) { return reportingType; }); 89 dbusIface.register_property_r( 90 "ReadingParameters", readingParameters, 91 sdbusplus::vtable::property_::const_, 92 [this](const auto&) { return readingParameters; }); 93 dbusIface.register_property_r( 94 "EmitsReadingsUpdate", emitsReadingsUpdate, 95 sdbusplus::vtable::property_::const_, 96 [this](const auto&) { return emitsReadingsUpdate; }); 97 dbusIface.register_property_r( 98 "LogToMetricReportsCollection", logToMetricReportsCollection, 99 sdbusplus::vtable::property_::const_, 100 [this](const auto&) { return logToMetricReportsCollection; }); 101 }); 102 103 if (reportingType == "Periodic") 104 { 105 scheduleTimer(interval); 106 } 107 } 108 109 void Report::timerProc(boost::system::error_code ec, Report& self) 110 { 111 if (ec) 112 { 113 return; 114 } 115 116 self.updateReadings(); 117 self.scheduleTimer(self.interval); 118 } 119 120 void Report::scheduleTimer(std::chrono::milliseconds timerInterval) 121 { 122 timer.expires_after(timerInterval); 123 timer.async_wait( 124 [this](boost::system::error_code ec) { timerProc(ec, *this); }); 125 } 126 127 void Report::updateReadings() 128 { 129 auto numElements = std::accumulate( 130 metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) { 131 return sum + metric->getReadings().size(); 132 }); 133 134 readingsCache.resize(numElements); 135 136 auto it = readingsCache.begin(); 137 138 for (const auto& metric : metrics) 139 { 140 for (const auto& reading : metric->getReadings()) 141 { 142 *(it++) = std::make_tuple(reading.id, reading.metadata, 143 reading.value, reading.timestamp); 144 } 145 } 146 147 std::get<0>(readings) = std::time(0); 148 std::get<1>(readings) = readingsCache; 149 150 reportIface->signal_property("Readings"); 151 } 152 153 bool Report::storeConfiguration() const 154 { 155 try 156 { 157 nlohmann::json data; 158 159 data["Version"] = reportVersion; 160 data["Name"] = name; 161 data["ReportingType"] = reportingType; 162 data["EmitsReadingsUpdate"] = emitsReadingsUpdate; 163 data["LogToMetricReportsCollection"] = logToMetricReportsCollection; 164 data["Interval"] = interval.count(); 165 data["ReadingParameters"] = utils::transform( 166 metrics, [](const auto& metric) { return metric->to_json(); }); 167 168 reportStorage.store(fileName, data); 169 } 170 catch (const std::exception& e) 171 { 172 phosphor::logging::log<phosphor::logging::level::ERR>( 173 "Failed to store a report in storage", 174 phosphor::logging::entry("msg=", e.what())); 175 return false; 176 } 177 178 return true; 179 } 180