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
eventLogObjectFromDBus(const dbus::utility::DBusPropertiesMap & map,EventLogObjectsType & event)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
dbusEventLogMatchHandlerSingleEntry(const dbus::utility::DBusPropertiesMap & map)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
onDbusEventLogCreated(sdbusplus::message_t & msg)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
DbusEventLogMonitor()103 DbusEventLogMonitor::DbusEventLogMonitor() :
104 dbusEventLogMonitor(*crow::connections::systemBus, propertiesMatchString,
105 onDbusEventLogCreated)
106
107 {}
108
getReadingsForReport(sdbusplus::message_t & msg)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
DbusTelemetryMonitor()154 DbusTelemetryMonitor::DbusTelemetryMonitor() :
155 matchTelemetryMonitor(*crow::connections::systemBus, telemetryMatchStr,
156 getReadingsForReport)
157 {}
158 } // namespace redfish
159