xref: /openbmc/bmcweb/features/redfish/src/dbus_log_watcher.cpp (revision 4a7a15c2d78e41ca571f990e071b9294a9f2a135)
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 static bool eventLogObjectFromDBus(const dbus::utility::DBusPropertiesMap& map,
26                                    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     // The order of 'AdditionalData' is not what's specified in an e.g.
42     // busctl call to create the Event Log Entry. So it cannot be used
43     // to map to the message args. Leaving this branch here for it to be
44     // implemented when the mapping is available
45 
46     return true;
47 }
48 
49 static void dbusEventLogMatchHandlerSingleEntry(
50     const dbus::utility::DBusPropertiesMap& map)
51 {
52     std::vector<EventLogObjectsType> eventRecords;
53     EventLogObjectsType& event = eventRecords.emplace_back();
54     bool success = eventLogObjectFromDBus(map, event);
55     if (!success)
56     {
57         BMCWEB_LOG_ERROR("Could not parse event log entry from dbus");
58         return;
59     }
60 
61     BMCWEB_LOG_DEBUG("Found Event Log Entry Id={}, Timestamp={}, Message={}",
62                      event.id, event.timestamp, event.messageId);
63     EventServiceManager::sendEventsToSubs(eventRecords);
64 }
65 
66 static void onDbusEventLogCreated(sdbusplus::message_t& msg)
67 {
68     BMCWEB_LOG_DEBUG("Handling new DBus Event Log Entry");
69 
70     sdbusplus::message::object_path objectPath;
71     dbus::utility::DBusInterfacesMap interfaces;
72 
73     msg.read(objectPath, interfaces);
74 
75     for (auto& pair : interfaces)
76     {
77         BMCWEB_LOG_DEBUG("Found dbus interface {}", pair.first);
78         if (pair.first == "xyz.openbmc_project.Logging.Entry")
79         {
80             const dbus::utility::DBusPropertiesMap& map = pair.second;
81             dbusEventLogMatchHandlerSingleEntry(map);
82         }
83     }
84 }
85 
86 const std::string propertiesMatchString =
87     sdbusplus::bus::match::rules::type::signal() +
88     sdbusplus::bus::match::rules::sender("xyz.openbmc_project.Logging") +
89     sdbusplus::bus::match::rules::interface(
90         "org.freedesktop.DBus.ObjectManager") +
91     sdbusplus::bus::match::rules::path("/xyz/openbmc_project/logging") +
92     sdbusplus::bus::match::rules::member("InterfacesAdded");
93 
94 DbusEventLogMonitor::DbusEventLogMonitor() :
95     dbusEventLogMonitor(*crow::connections::systemBus, propertiesMatchString,
96                         onDbusEventLogCreated)
97 
98 {}
99 
100 static void getReadingsForReport(sdbusplus::message_t& msg)
101 {
102     if (msg.is_method_error())
103     {
104         BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
105         return;
106     }
107 
108     sdbusplus::message::object_path path(msg.get_path());
109     std::string id = path.filename();
110     if (id.empty())
111     {
112         BMCWEB_LOG_ERROR("Failed to get Id from path");
113         return;
114     }
115 
116     std::string interface;
117     dbus::utility::DBusPropertiesMap props;
118     std::vector<std::string> invalidProps;
119     msg.read(interface, props, invalidProps);
120 
121     auto found = std::ranges::find_if(props, [](const auto& x) {
122         return x.first == "Readings";
123     });
124     if (found == props.end())
125     {
126         BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
127         return;
128     }
129 
130     const telemetry::TimestampReadings* readings =
131         std::get_if<telemetry::TimestampReadings>(&found->second);
132     if (readings == nullptr)
133     {
134         BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
135         return;
136     }
137     EventServiceManager::sendTelemetryReportToSubs(id, *readings);
138 }
139 
140 const std::string telemetryMatchStr =
141     "type='signal',member='PropertiesChanged',"
142     "interface='org.freedesktop.DBus.Properties',"
143     "arg0=xyz.openbmc_project.Telemetry.Report";
144 
145 DbusTelemetryMonitor::DbusTelemetryMonitor() :
146     matchTelemetryMonitor(*crow::connections::systemBus, telemetryMatchStr,
147                           getReadingsForReport)
148 {}
149 } // namespace redfish
150