xref: /openbmc/bmcweb/redfish-core/src/dbus_log_watcher.cpp (revision 56431b29998d58c43b101b5f55401e505c85be5e)
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