xref: /openbmc/bmcweb/features/redfish/src/dbus_log_watcher.cpp (revision 546d07851b04704b3e27a7b752acdb00a5c07d2c)
1b26ff34dSEd Tanous #include "dbus_log_watcher.hpp"
2b26ff34dSEd Tanous 
32ac69850SEd Tanous #include "dbus_singleton.hpp"
4b26ff34dSEd Tanous #include "dbus_utility.hpp"
56c58a03eSAlexander Hansen #include "event_logs_object_type.hpp"
6b26ff34dSEd Tanous #include "event_service_manager.hpp"
7b26ff34dSEd Tanous #include "logging.hpp"
8b26ff34dSEd Tanous #include "metric_report.hpp"
96c58a03eSAlexander Hansen #include "utils/dbus_event_log_entry.hpp"
104a7a15c2SAlexander Hansen #include "utils/time_utils.hpp"
11b26ff34dSEd Tanous 
122ac69850SEd Tanous #include <sdbusplus/bus/match.hpp>
13b26ff34dSEd Tanous #include <sdbusplus/message.hpp>
14b26ff34dSEd Tanous #include <sdbusplus/message/native_types.hpp>
15b26ff34dSEd Tanous 
16b26ff34dSEd Tanous #include <algorithm>
176c58a03eSAlexander Hansen #include <optional>
18b26ff34dSEd Tanous #include <string>
19b26ff34dSEd Tanous #include <variant>
20b26ff34dSEd Tanous #include <vector>
21b26ff34dSEd Tanous 
22b26ff34dSEd Tanous namespace redfish
23b26ff34dSEd Tanous {
244a7a15c2SAlexander Hansen 
256c58a03eSAlexander Hansen static bool eventLogObjectFromDBus(const dbus::utility::DBusPropertiesMap& map,
266c58a03eSAlexander Hansen                                    EventLogObjectsType& event)
276c58a03eSAlexander Hansen {
286c58a03eSAlexander Hansen     std::optional<DbusEventLogEntry> optEntry =
296c58a03eSAlexander Hansen         fillDbusEventLogEntryFromPropertyMap(map);
306c58a03eSAlexander Hansen 
316c58a03eSAlexander Hansen     if (!optEntry.has_value())
326c58a03eSAlexander Hansen     {
336c58a03eSAlexander Hansen         BMCWEB_LOG_ERROR(
346c58a03eSAlexander Hansen             "Could not construct event log entry from dbus properties");
356c58a03eSAlexander Hansen         return false;
366c58a03eSAlexander Hansen     }
376c58a03eSAlexander Hansen     DbusEventLogEntry& entry = optEntry.value();
386c58a03eSAlexander Hansen     event.id = std::to_string(entry.Id);
394a7a15c2SAlexander Hansen     event.timestamp = redfish::time_utils::getDateTimeUintMs(entry.Timestamp);
406c58a03eSAlexander Hansen 
41*546d0785SAlexander Hansen     // This dbus property is not documented to contain the Redfish Message Id,
42*546d0785SAlexander Hansen     // but can be used as such. As a temporary solution that is sufficient,
43*546d0785SAlexander Hansen     // the event filtering code will drop the event anyways if event.messageId
44*546d0785SAlexander Hansen     // is not valid.
45*546d0785SAlexander Hansen     //
46*546d0785SAlexander Hansen     // This will need resolved before
47*546d0785SAlexander Hansen     // experimental-redfish-dbus-log-subscription is stabilized
48*546d0785SAlexander Hansen     event.messageId = entry.Message;
49*546d0785SAlexander Hansen 
506c58a03eSAlexander Hansen     // The order of 'AdditionalData' is not what's specified in an e.g.
516c58a03eSAlexander Hansen     // busctl call to create the Event Log Entry. So it cannot be used
526c58a03eSAlexander Hansen     // to map to the message args. Leaving this branch here for it to be
536c58a03eSAlexander Hansen     // implemented when the mapping is available
546c58a03eSAlexander Hansen 
556c58a03eSAlexander Hansen     return true;
566c58a03eSAlexander Hansen }
576c58a03eSAlexander Hansen 
586c58a03eSAlexander Hansen static void dbusEventLogMatchHandlerSingleEntry(
596c58a03eSAlexander Hansen     const dbus::utility::DBusPropertiesMap& map)
606c58a03eSAlexander Hansen {
616c58a03eSAlexander Hansen     std::vector<EventLogObjectsType> eventRecords;
626c58a03eSAlexander Hansen     EventLogObjectsType& event = eventRecords.emplace_back();
636c58a03eSAlexander Hansen     bool success = eventLogObjectFromDBus(map, event);
646c58a03eSAlexander Hansen     if (!success)
656c58a03eSAlexander Hansen     {
666c58a03eSAlexander Hansen         BMCWEB_LOG_ERROR("Could not parse event log entry from dbus");
676c58a03eSAlexander Hansen         return;
686c58a03eSAlexander Hansen     }
696c58a03eSAlexander Hansen 
706c58a03eSAlexander Hansen     BMCWEB_LOG_DEBUG("Found Event Log Entry Id={}, Timestamp={}, Message={}",
716c58a03eSAlexander Hansen                      event.id, event.timestamp, event.messageId);
726c58a03eSAlexander Hansen     EventServiceManager::sendEventsToSubs(eventRecords);
736c58a03eSAlexander Hansen }
746c58a03eSAlexander Hansen 
756c58a03eSAlexander Hansen static void onDbusEventLogCreated(sdbusplus::message_t& msg)
766c58a03eSAlexander Hansen {
776c58a03eSAlexander Hansen     BMCWEB_LOG_DEBUG("Handling new DBus Event Log Entry");
786c58a03eSAlexander Hansen 
796c58a03eSAlexander Hansen     sdbusplus::message::object_path objectPath;
806c58a03eSAlexander Hansen     dbus::utility::DBusInterfacesMap interfaces;
816c58a03eSAlexander Hansen 
826c58a03eSAlexander Hansen     msg.read(objectPath, interfaces);
836c58a03eSAlexander Hansen 
846c58a03eSAlexander Hansen     for (auto& pair : interfaces)
856c58a03eSAlexander Hansen     {
866c58a03eSAlexander Hansen         BMCWEB_LOG_DEBUG("Found dbus interface {}", pair.first);
876c58a03eSAlexander Hansen         if (pair.first == "xyz.openbmc_project.Logging.Entry")
886c58a03eSAlexander Hansen         {
896c58a03eSAlexander Hansen             const dbus::utility::DBusPropertiesMap& map = pair.second;
906c58a03eSAlexander Hansen             dbusEventLogMatchHandlerSingleEntry(map);
916c58a03eSAlexander Hansen         }
926c58a03eSAlexander Hansen     }
936c58a03eSAlexander Hansen }
946c58a03eSAlexander Hansen 
956c58a03eSAlexander Hansen const std::string propertiesMatchString =
966c58a03eSAlexander Hansen     sdbusplus::bus::match::rules::type::signal() +
976c58a03eSAlexander Hansen     sdbusplus::bus::match::rules::sender("xyz.openbmc_project.Logging") +
986c58a03eSAlexander Hansen     sdbusplus::bus::match::rules::interface(
996c58a03eSAlexander Hansen         "org.freedesktop.DBus.ObjectManager") +
1006c58a03eSAlexander Hansen     sdbusplus::bus::match::rules::path("/xyz/openbmc_project/logging") +
1016c58a03eSAlexander Hansen     sdbusplus::bus::match::rules::member("InterfacesAdded");
1026c58a03eSAlexander Hansen 
1036c58a03eSAlexander Hansen DbusEventLogMonitor::DbusEventLogMonitor() :
1046c58a03eSAlexander Hansen     dbusEventLogMonitor(*crow::connections::systemBus, propertiesMatchString,
1056c58a03eSAlexander Hansen                         onDbusEventLogCreated)
1066c58a03eSAlexander Hansen 
1076c58a03eSAlexander Hansen {}
1086c58a03eSAlexander Hansen 
1092ac69850SEd Tanous static void getReadingsForReport(sdbusplus::message_t& msg)
110b26ff34dSEd Tanous {
111b26ff34dSEd Tanous     if (msg.is_method_error())
112b26ff34dSEd Tanous     {
113b26ff34dSEd Tanous         BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
114b26ff34dSEd Tanous         return;
115b26ff34dSEd Tanous     }
116b26ff34dSEd Tanous 
117b26ff34dSEd Tanous     sdbusplus::message::object_path path(msg.get_path());
118b26ff34dSEd Tanous     std::string id = path.filename();
119b26ff34dSEd Tanous     if (id.empty())
120b26ff34dSEd Tanous     {
121b26ff34dSEd Tanous         BMCWEB_LOG_ERROR("Failed to get Id from path");
122b26ff34dSEd Tanous         return;
123b26ff34dSEd Tanous     }
124b26ff34dSEd Tanous 
125b26ff34dSEd Tanous     std::string interface;
126b26ff34dSEd Tanous     dbus::utility::DBusPropertiesMap props;
127b26ff34dSEd Tanous     std::vector<std::string> invalidProps;
128b26ff34dSEd Tanous     msg.read(interface, props, invalidProps);
129b26ff34dSEd Tanous 
130b26ff34dSEd Tanous     auto found = std::ranges::find_if(props, [](const auto& x) {
131b26ff34dSEd Tanous         return x.first == "Readings";
132b26ff34dSEd Tanous     });
133b26ff34dSEd Tanous     if (found == props.end())
134b26ff34dSEd Tanous     {
135b26ff34dSEd Tanous         BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
136b26ff34dSEd Tanous         return;
137b26ff34dSEd Tanous     }
138b26ff34dSEd Tanous 
139b26ff34dSEd Tanous     const telemetry::TimestampReadings* readings =
140b26ff34dSEd Tanous         std::get_if<telemetry::TimestampReadings>(&found->second);
141b26ff34dSEd Tanous     if (readings == nullptr)
142b26ff34dSEd Tanous     {
143b26ff34dSEd Tanous         BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
144b26ff34dSEd Tanous         return;
145b26ff34dSEd Tanous     }
146b26ff34dSEd Tanous     EventServiceManager::sendTelemetryReportToSubs(id, *readings);
147b26ff34dSEd Tanous }
1482ac69850SEd Tanous 
1492ac69850SEd Tanous const std::string telemetryMatchStr =
1502ac69850SEd Tanous     "type='signal',member='PropertiesChanged',"
1512ac69850SEd Tanous     "interface='org.freedesktop.DBus.Properties',"
1522ac69850SEd Tanous     "arg0=xyz.openbmc_project.Telemetry.Report";
1532ac69850SEd Tanous 
1542ac69850SEd Tanous DbusTelemetryMonitor::DbusTelemetryMonitor() :
1552ac69850SEd Tanous     matchTelemetryMonitor(*crow::connections::systemBus, telemetryMatchStr,
1562ac69850SEd Tanous                           getReadingsForReport)
1572ac69850SEd Tanous {}
158b26ff34dSEd Tanous } // namespace redfish
159