1 #include "dbus_log_watcher.hpp" 2 3 #include "dbus_singleton.hpp" 4 #include "dbus_utility.hpp" 5 #include "event_logs_object_type.hpp" 6 #include "event_service_manager.hpp" 7 #include "logging.hpp" 8 #include "metric_report.hpp" 9 #include "utils/dbus_event_log_entry.hpp" 10 #include "utils/time_utils.hpp" 11 12 #include <sdbusplus/bus/match.hpp> 13 #include <sdbusplus/message.hpp> 14 #include <sdbusplus/message/native_types.hpp> 15 16 #include <algorithm> 17 #include <optional> 18 #include <string> 19 #include <variant> 20 #include <vector> 21 22 namespace redfish 23 { 24 25 bool DbusEventLogMonitor::eventLogObjectFromDBus( 26 const dbus::utility::DBusPropertiesMap& map, EventLogObjectsType& event) 27 { 28 std::optional<DbusEventLogEntry> optEntry = 29 fillDbusEventLogEntryFromPropertyMap(map); 30 31 if (!optEntry.has_value()) 32 { 33 BMCWEB_LOG_ERROR( 34 "Could not construct event log entry from dbus properties"); 35 return false; 36 } 37 DbusEventLogEntry& entry = optEntry.value(); 38 event.id = std::to_string(entry.Id); 39 event.timestamp = redfish::time_utils::getDateTimeUintMs(entry.Timestamp); 40 41 // This dbus property is not documented to contain the Redfish Message Id, 42 // but can be used as such. As a temporary solution that is sufficient, 43 // the event filtering code will drop the event anyways if event.messageId 44 // is not valid. 45 // 46 // This will need resolved before 47 // experimental-redfish-dbus-log-subscription is stabilized 48 event.messageId = entry.Message; 49 50 // The order of 'AdditionalData' is not what's specified in an e.g. 51 // busctl call to create the Event Log Entry. So it cannot be used 52 // to map to the message args. Leaving this branch here for it to be 53 // implemented when the mapping is available 54 55 return true; 56 } 57 58 static void dbusEventLogMatchHandlerSingleEntry( 59 const dbus::utility::DBusPropertiesMap& map) 60 { 61 std::vector<EventLogObjectsType> eventRecords; 62 EventLogObjectsType& event = eventRecords.emplace_back(); 63 bool success = DbusEventLogMonitor::eventLogObjectFromDBus(map, event); 64 if (!success) 65 { 66 BMCWEB_LOG_ERROR("Could not parse event log entry from dbus"); 67 return; 68 } 69 70 BMCWEB_LOG_DEBUG("Found Event Log Entry Id={}, Timestamp={}, Message={}", 71 event.id, event.timestamp, event.messageId); 72 EventServiceManager::sendEventsToSubs(eventRecords); 73 } 74 75 static void onDbusEventLogCreated(sdbusplus::message_t& msg) 76 { 77 BMCWEB_LOG_DEBUG("Handling new DBus Event Log Entry"); 78 79 sdbusplus::message::object_path objectPath; 80 dbus::utility::DBusInterfacesMap interfaces; 81 82 msg.read(objectPath, interfaces); 83 84 for (auto& pair : interfaces) 85 { 86 BMCWEB_LOG_DEBUG("Found dbus interface {}", pair.first); 87 if (pair.first == "xyz.openbmc_project.Logging.Entry") 88 { 89 const dbus::utility::DBusPropertiesMap& map = pair.second; 90 dbusEventLogMatchHandlerSingleEntry(map); 91 } 92 } 93 } 94 95 const std::string propertiesMatchString = 96 sdbusplus::bus::match::rules::type::signal() + 97 sdbusplus::bus::match::rules::sender("xyz.openbmc_project.Logging") + 98 sdbusplus::bus::match::rules::interface( 99 "org.freedesktop.DBus.ObjectManager") + 100 sdbusplus::bus::match::rules::path("/xyz/openbmc_project/logging") + 101 sdbusplus::bus::match::rules::member("InterfacesAdded"); 102 103 DbusEventLogMonitor::DbusEventLogMonitor() : 104 dbusEventLogMonitor(*crow::connections::systemBus, propertiesMatchString, 105 onDbusEventLogCreated) 106 107 {} 108 109 static void getReadingsForReport(sdbusplus::message_t& msg) 110 { 111 if (msg.is_method_error()) 112 { 113 BMCWEB_LOG_ERROR("TelemetryMonitor Signal error"); 114 return; 115 } 116 117 sdbusplus::message::object_path path(msg.get_path()); 118 std::string id = path.filename(); 119 if (id.empty()) 120 { 121 BMCWEB_LOG_ERROR("Failed to get Id from path"); 122 return; 123 } 124 125 std::string interface; 126 dbus::utility::DBusPropertiesMap props; 127 std::vector<std::string> invalidProps; 128 msg.read(interface, props, invalidProps); 129 130 auto found = std::ranges::find_if(props, [](const auto& x) { 131 return x.first == "Readings"; 132 }); 133 if (found == props.end()) 134 { 135 BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 136 return; 137 } 138 139 const telemetry::TimestampReadings* readings = 140 std::get_if<telemetry::TimestampReadings>(&found->second); 141 if (readings == nullptr) 142 { 143 BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 144 return; 145 } 146 EventServiceManager::sendTelemetryReportToSubs(id, *readings); 147 } 148 149 const std::string telemetryMatchStr = 150 "type='signal',member='PropertiesChanged'," 151 "interface='org.freedesktop.DBus.Properties'," 152 "arg0=xyz.openbmc_project.Telemetry.Report"; 153 154 DbusTelemetryMonitor::DbusTelemetryMonitor() : 155 matchTelemetryMonitor(*crow::connections::systemBus, telemetryMatchStr, 156 getReadingsForReport) 157 {} 158 } // namespace redfish 159