Created metric class
Metric collects updates from sensor. Report displays metric readings
depending on reportingType.
Tested:
- Added new units tests for Metric class
- All other unit tests are passing
Change-Id: I19f4831fab163a4f9540cef7bb23e903ae90fddf
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/interfaces/metric.hpp b/src/interfaces/metric.hpp
index 50bf5d5..d63c979 100644
--- a/src/interfaces/metric.hpp
+++ b/src/interfaces/metric.hpp
@@ -14,6 +14,7 @@
public:
virtual ~Metric() = default;
+ virtual void initialize() = 0;
virtual const std::vector<MetricValue>& getReadings() const = 0;
virtual nlohmann::json to_json() const = 0;
};
diff --git a/src/metric.cpp b/src/metric.cpp
index b40da5a..8d9f19b 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -1 +1,64 @@
#include "metric.hpp"
+
+#include "interfaces/types.hpp"
+#include "utils/transform.hpp"
+
+#include <algorithm>
+
+Metric::Metric(std::vector<std::shared_ptr<interfaces::Sensor>> sensors,
+ std::string operationType, std::string id,
+ std::string metadata) :
+ sensors(std::move(sensors)),
+ operationType(std::move(operationType)), id(std::move(id)),
+ metadata(std::move(metadata))
+{}
+
+void Metric::initialize()
+{
+ readings = std::vector<MetricValue>(sensors.size(),
+ MetricValue{id, metadata, 0., 0u});
+
+ for (auto& sensor : sensors)
+ {
+ sensor->registerForUpdates(weak_from_this());
+ }
+}
+
+const std::vector<MetricValue>& Metric::getReadings() const
+{
+ return readings;
+}
+
+void Metric::sensorUpdated(interfaces::Sensor& sensor, uint64_t timestamp)
+{
+ MetricValue& mv = findMetric(sensor);
+ mv.timestamp = timestamp;
+}
+
+void Metric::sensorUpdated(interfaces::Sensor& sensor, uint64_t timestamp,
+ double value)
+{
+ MetricValue& mv = findMetric(sensor);
+ mv.timestamp = timestamp;
+ mv.value = value;
+}
+
+MetricValue& Metric::findMetric(interfaces::Sensor& sensor)
+{
+ auto it =
+ std::find_if(sensors.begin(), sensors.end(),
+ [&sensor](const auto& s) { return s.get() == &sensor; });
+ auto index = std::distance(sensors.begin(), it);
+ return readings.at(index);
+}
+
+nlohmann::json Metric::to_json() const
+{
+ auto sensorPaths = utils::transform(
+ sensors, [](const auto& sensor) -> sdbusplus::message::object_path {
+ return sdbusplus::message::object_path(sensor->id().service + ":" +
+ sensor->id().path);
+ });
+ return LabeledReadingParameter::to_json(ReadingParameters::value_type(
+ std::move(sensorPaths), operationType, id, metadata));
+}
diff --git a/src/metric.hpp b/src/metric.hpp
index 76a60fb..6e27446 100644
--- a/src/metric.hpp
+++ b/src/metric.hpp
@@ -1,21 +1,30 @@
#pragma once
#include "interfaces/metric.hpp"
+#include "interfaces/sensor.hpp"
#include "interfaces/sensor_listener.hpp"
-class Metric : public interfaces::Metric, public interfaces::SensorListener
+class Metric :
+ public interfaces::Metric,
+ public interfaces::SensorListener,
+ public std::enable_shared_from_this<Metric>
{
public:
- const std::vector<MetricValue>& getReadings() const override
- {
- return readings;
- }
+ Metric(std::vector<std::shared_ptr<interfaces::Sensor>> sensors,
+ std::string operationType, std::string id, std::string metadata);
- void sensorUpdated(interfaces::Sensor&, uint64_t) override
- {}
- void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override
- {}
+ void initialize() override;
+ const std::vector<MetricValue>& getReadings() const override;
+ void sensorUpdated(interfaces::Sensor&, uint64_t) override;
+ void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override;
+ nlohmann::json to_json() const override;
private:
+ MetricValue& findMetric(interfaces::Sensor&);
+
+ std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+ std::string operationType;
+ std::string id;
+ std::string metadata;
std::vector<MetricValue> readings;
};
diff --git a/src/report.cpp b/src/report.cpp
index 6698ec3..c1b7d5f 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -27,6 +27,11 @@
fileName(std::to_string(std::hash<std::string>{}(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] {
@@ -137,7 +142,7 @@
return sum + metric->getReadings().size();
});
- readingsCache.resize(numElements);
+ std::tuple_element_t<1, Readings> readingsCache(numElements);
auto it = readingsCache.begin();
@@ -151,7 +156,7 @@
}
std::get<0>(readings) = std::time(0);
- std::get<1>(readings) = readingsCache;
+ std::get<1>(readings) = std::move(readingsCache);
reportIface->signal_property("Readings");
}
diff --git a/src/report.hpp b/src/report.hpp
index 2020f99..b227392 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -59,7 +59,6 @@
ReadingParameters readingParameters;
bool persistency;
Readings readings = {};
- std::tuple_element_t<1, Readings> readingsCache = {};
std::shared_ptr<sdbusplus::asio::object_server> objServer;
std::unique_ptr<sdbusplus::asio::dbus_interface> reportIface;
std::unique_ptr<sdbusplus::asio::dbus_interface> deleteIface;
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index 5ac32f3..e4689aa 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -1,5 +1,6 @@
#include "report_factory.hpp"
+#include "metric.hpp"
#include "report.hpp"
#include "sensor.hpp"
#include "utils/transform.hpp"
@@ -19,10 +20,84 @@
interfaces::ReportManager& reportManager,
interfaces::JsonStorage& reportStorage) const
{
+ std::optional<std::vector<ReportFactory::SensorTree>> sensorTree;
+
std::vector<std::shared_ptr<interfaces::Metric>> metrics;
+ metrics.reserve(metricParams.size());
+
+ for (const auto& [sensorPaths, op, id, metadata] : metricParams)
+ {
+ if (!sensorTree && yield && sensorPaths.size() > 0)
+ {
+ sensorTree = getSensorTree(*yield);
+ }
+
+ std::vector<std::shared_ptr<interfaces::Sensor>> sensors =
+ getSensors(sensorTree, sensorPaths);
+
+ metrics.emplace_back(
+ std::make_shared<Metric>(std::move(sensors), op, id, metadata));
+ }
return std::make_unique<Report>(
bus->get_io_context(), objServer, name, reportingType,
emitsReadingsSignal, logToMetricReportsCollection, period, metricParams,
reportManager, reportStorage, std::move(metrics));
}
+
+std::vector<std::shared_ptr<interfaces::Sensor>> ReportFactory::getSensors(
+ const std::optional<std::vector<ReportFactory::SensorTree>>& tree,
+ const std::vector<sdbusplus::message::object_path>& sensorPaths) const
+{
+ if (tree)
+ {
+ std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+
+ for (const auto& [sensor, ifacesMap] : *tree)
+ {
+ auto it = std::find(sensorPaths.begin(), sensorPaths.end(), sensor);
+ if (it != sensorPaths.end())
+ {
+ for (const auto& [service, ifaces] : ifacesMap)
+ {
+ sensors.emplace_back(sensorCache.makeSensor<Sensor>(
+ service, sensor, bus->get_io_context(), bus));
+ }
+ }
+ }
+
+ return sensors;
+ }
+ else
+ {
+ return utils::transform(
+ sensorPaths,
+ [this](const std::string& sensor)
+ -> std::shared_ptr<interfaces::Sensor> {
+ std::string::size_type pos = sensor.find_first_of(":");
+ auto service = sensor.substr(0, pos);
+ auto path = sensor.substr(pos + 1);
+ return sensorCache.makeSensor<Sensor>(
+ service, path, bus->get_io_context(), bus);
+ });
+ }
+}
+
+std::vector<ReportFactory::SensorTree>
+ ReportFactory::getSensorTree(boost::asio::yield_context& yield) const
+{
+ std::array<const char*, 1> interfaces = {
+ "xyz.openbmc_project.Sensor.Value"};
+ boost::system::error_code ec;
+
+ auto result = bus->yield_method_call<std::vector<SensorTree>>(
+ yield, ec, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/sensors", 2, interfaces);
+ if (ec)
+ {
+ throw std::runtime_error("failed");
+ }
+ return result;
+}
diff --git a/src/report_factory.hpp b/src/report_factory.hpp
index bdf9268..0346441 100644
--- a/src/report_factory.hpp
+++ b/src/report_factory.hpp
@@ -2,6 +2,7 @@
#include "interfaces/report_factory.hpp"
#include "interfaces/sensor.hpp"
+#include "sensor_cache.hpp"
#include <boost/asio/io_context.hpp>
#include <sdbusplus/asio/object_server.hpp>
@@ -22,6 +23,19 @@
interfaces::JsonStorage& reportStorage) const override;
private:
+ using SensorPath = std::string;
+ using ServiceName = std::string;
+ using Ifaces = std::vector<std::string>;
+ using SensorIfaces = std::vector<std::pair<ServiceName, Ifaces>>;
+ using SensorTree = std::pair<SensorPath, SensorIfaces>;
+
+ std::vector<std::shared_ptr<interfaces::Sensor>> getSensors(
+ const std::optional<std::vector<SensorTree>>& tree,
+ const std::vector<sdbusplus::message::object_path>& sensorPaths) const;
+ std::vector<SensorTree>
+ getSensorTree(boost::asio::yield_context& yield) const;
+
std::shared_ptr<sdbusplus::asio::connection> bus;
std::shared_ptr<sdbusplus::asio::object_server> objServer;
+ mutable SensorCache sensorCache;
};
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index d23b589..eb2d767 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -16,6 +16,7 @@
reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
{
reports.reserve(maxReports);
+
loadFromPersistent();
reportManagerIface = objServer->add_unique_interface(
diff --git a/src/telemetry.hpp b/src/telemetry.hpp
index 4a6a6b0..4cc138e 100644
--- a/src/telemetry.hpp
+++ b/src/telemetry.hpp
@@ -3,6 +3,7 @@
#include "persistent_json_storage.hpp"
#include "report_factory.hpp"
#include "report_manager.hpp"
+#include "sensor_cache.hpp"
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>