event service: dbus log: enable event subscription

enable the event subscriptions

/redfish/v1/EventService/Subscriptions/

to work for the dbus event log.

So if you are enabling redfish-dbus-log option,
event subscriptions should work similar to when
this option is disabled, with one difference:

- 'MessageArgs' property is currently not implemented and cannot be
found in the returned json.

Tested:
- Using Redfish Event Listener, test subscriptions and eventing.
- Manual Test below with the Redfish Event Listener:

1. Created a maximal Event Log Subscription

redfish
{
"@odata.id": "/redfish/v1/EventService/Subscriptions/2023893979",
"@odata.type": "#EventDestination.v1_8_0.EventDestination",
"Context": "EventLogSubscription",
"DeliveryRetryPolicy": "TerminateAfterRetries",
"Destination": "http://${ip}:5000/event-receiver",
"EventFormatType": "Event",
"HttpHeaders": [],
"Id": "2023893979",
"MessageIds": [],
"MetricReportDefinitions": [],
"Name": "Event Destination 2023893979",
"Protocol": "Redfish",
"RegistryPrefixes": [],
"ResourceTypes": [],
"SubscriptionType": "RedfishEvent",
"VerifyCertificate": true
}

which matches on all registries and all message ids.

2. created a new phosphor-logging entry

busctl call xyz.openbmc_project.Logging \
/xyz/openbmc_project/logging \
xyz.openbmc_project.Logging.Create \
Create 'ssa{ss}' \
OpenBMC.0.1.PowerButtonPressed \
xyz.openbmc_project.Logging.Entry.Level.Error 0

3. bmcweb picks up this new entry via the dbus match, this can be
verified by putting bmcweb in debug logging mode.

4. the event log entry makes it through the filtering code

5. the POST request is sent to the subscribed server as expected,
and contains the same properties as with the file-based backend.

Change-Id: I122e1121389f72e67a998706aeadd052ae607d60
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/config/meson.build b/config/meson.build
index 0f08bcf..d338b77 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -7,6 +7,7 @@
     'cookie-auth',
     'experimental-http2',
     'experimental-redfish-multi-computer-system',
+    'experimental-redfish-dbus-log-subscription',
     'google-api',
     'host-serial-socket',
     'hypervisor-computer-system',
diff --git a/meson.options b/meson.options
index 4725e79..d5b44bd 100644
--- a/meson.options
+++ b/meson.options
@@ -115,6 +115,21 @@
                     /redfish/v1/Systems/system/LogServices/EventLog/Entries''',
 )
 
+# BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION
+option(
+    'experimental-redfish-dbus-log-subscription',
+    type: 'feature',
+    value: 'disabled',
+    description: '''
+        Allows EventService subscriptions when the redfish-dbus-log option is
+        enabled.
+        This option is currently non-functional, given Redfish requirements for
+        MessageId support in Events.
+        Option will be removed begining of Q2-2025.
+        Should not be enabled on any production systems.
+    ''',
+)
+
 # BMCWEB_REDFISH_HOST_LOGGER
 option(
     'redfish-host-logger',
diff --git a/redfish-core/include/dbus_log_watcher.hpp b/redfish-core/include/dbus_log_watcher.hpp
index b47fca7..233b9be 100644
--- a/redfish-core/include/dbus_log_watcher.hpp
+++ b/redfish-core/include/dbus_log_watcher.hpp
@@ -3,6 +3,13 @@
 #include <sdbusplus/bus/match.hpp>
 namespace redfish
 {
+class DbusEventLogMonitor
+{
+  public:
+    DbusEventLogMonitor();
+    sdbusplus::bus::match_t dbusEventLogMonitor;
+};
+
 class DbusTelemetryMonitor
 {
   public:
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 78ecae9..a2b1788 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -65,6 +65,7 @@
 
     size_t noOfEventLogSubscribers{0};
     size_t noOfMetricReportSubscribers{0};
+    std::optional<DbusEventLogMonitor> dbusEventLogMonitor;
     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
@@ -262,7 +263,18 @@
         {
             if (noOfEventLogSubscribers > 0U)
             {
-                if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
+                if constexpr (BMCWEB_REDFISH_DBUS_LOG)
+                {
+                    if (!dbusEventLogMonitor)
+                    {
+                        if constexpr (
+                            BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
+                        {
+                            dbusEventLogMonitor.emplace();
+                        }
+                    }
+                }
+                else
                 {
                     if (!filesystemLogMonitor)
                     {
@@ -272,6 +284,7 @@
             }
             else
             {
+                dbusEventLogMonitor.reset();
                 filesystemLogMonitor.reset();
             }
 
@@ -290,6 +303,7 @@
         else
         {
             matchTelemetryMonitor.reset();
+            dbusEventLogMonitor.reset();
             filesystemLogMonitor.reset();
         }
 
@@ -346,23 +360,43 @@
                 metricReportSubCount++;
             }
         }
-
         noOfEventLogSubscribers = eventLogSubCount;
-        if (noOfMetricReportSubscribers != metricReportSubCount)
+        if (eventLogSubCount > 0U)
         {
-            noOfMetricReportSubscribers = metricReportSubCount;
-            if (noOfMetricReportSubscribers != 0U)
+            if constexpr (BMCWEB_REDFISH_DBUS_LOG)
             {
-                if (!matchTelemetryMonitor)
+                if (!dbusEventLogMonitor &&
+                    BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
                 {
-                    matchTelemetryMonitor.emplace();
+                    dbusEventLogMonitor.emplace();
                 }
             }
             else
             {
-                matchTelemetryMonitor.reset();
+                if (!filesystemLogMonitor)
+                {
+                    filesystemLogMonitor.emplace(ioc);
+                }
             }
         }
+        else
+        {
+            dbusEventLogMonitor.reset();
+            filesystemLogMonitor.reset();
+        }
+
+        noOfMetricReportSubscribers = metricReportSubCount;
+        if (metricReportSubCount > 0U)
+        {
+            if (!matchTelemetryMonitor)
+            {
+                matchTelemetryMonitor.emplace();
+            }
+        }
+        else
+        {
+            matchTelemetryMonitor.reset();
+        }
     }
 
     std::shared_ptr<Subscription> getSubscription(const std::string& id)
diff --git a/redfish-core/src/dbus_log_watcher.cpp b/redfish-core/src/dbus_log_watcher.cpp
index c2eab64..b1e8455 100644
--- a/redfish-core/src/dbus_log_watcher.cpp
+++ b/redfish-core/src/dbus_log_watcher.cpp
@@ -2,21 +2,98 @@
 
 #include "dbus_singleton.hpp"
 #include "dbus_utility.hpp"
+#include "event_logs_object_type.hpp"
 #include "event_service_manager.hpp"
 #include "logging.hpp"
 #include "metric_report.hpp"
+#include "utils/dbus_event_log_entry.hpp"
 
 #include <sdbusplus/bus/match.hpp>
 #include <sdbusplus/message.hpp>
 #include <sdbusplus/message/native_types.hpp>
 
 #include <algorithm>
+#include <optional>
 #include <string>
 #include <variant>
 #include <vector>
 
 namespace redfish
 {
+static bool eventLogObjectFromDBus(const dbus::utility::DBusPropertiesMap& map,
+                                   EventLogObjectsType& event)
+{
+    std::optional<DbusEventLogEntry> optEntry =
+        fillDbusEventLogEntryFromPropertyMap(map);
+
+    if (!optEntry.has_value())
+    {
+        BMCWEB_LOG_ERROR(
+            "Could not construct event log entry from dbus properties");
+        return false;
+    }
+    DbusEventLogEntry& entry = optEntry.value();
+    event.id = std::to_string(entry.Id);
+
+    // The order of 'AdditionalData' is not what's specified in an e.g.
+    // busctl call to create the Event Log Entry. So it cannot be used
+    // to map to the message args. Leaving this branch here for it to be
+    // implemented when the mapping is available
+
+    return true;
+}
+
+static void dbusEventLogMatchHandlerSingleEntry(
+    const dbus::utility::DBusPropertiesMap& map)
+{
+    std::vector<EventLogObjectsType> eventRecords;
+    EventLogObjectsType& event = eventRecords.emplace_back();
+    bool success = eventLogObjectFromDBus(map, event);
+    if (!success)
+    {
+        BMCWEB_LOG_ERROR("Could not parse event log entry from dbus");
+        return;
+    }
+
+    BMCWEB_LOG_DEBUG("Found Event Log Entry Id={}, Timestamp={}, Message={}",
+                     event.id, event.timestamp, event.messageId);
+    EventServiceManager::sendEventsToSubs(eventRecords);
+}
+
+static void onDbusEventLogCreated(sdbusplus::message_t& msg)
+{
+    BMCWEB_LOG_DEBUG("Handling new DBus Event Log Entry");
+
+    sdbusplus::message::object_path objectPath;
+    dbus::utility::DBusInterfacesMap interfaces;
+
+    msg.read(objectPath, interfaces);
+
+    for (auto& pair : interfaces)
+    {
+        BMCWEB_LOG_DEBUG("Found dbus interface {}", pair.first);
+        if (pair.first == "xyz.openbmc_project.Logging.Entry")
+        {
+            const dbus::utility::DBusPropertiesMap& map = pair.second;
+            dbusEventLogMatchHandlerSingleEntry(map);
+        }
+    }
+}
+
+const std::string propertiesMatchString =
+    sdbusplus::bus::match::rules::type::signal() +
+    sdbusplus::bus::match::rules::sender("xyz.openbmc_project.Logging") +
+    sdbusplus::bus::match::rules::interface(
+        "org.freedesktop.DBus.ObjectManager") +
+    sdbusplus::bus::match::rules::path("/xyz/openbmc_project/logging") +
+    sdbusplus::bus::match::rules::member("InterfacesAdded");
+
+DbusEventLogMonitor::DbusEventLogMonitor() :
+    dbusEventLogMonitor(*crow::connections::systemBus, propertiesMatchString,
+                        onDbusEventLogCreated)
+
+{}
+
 static void getReadingsForReport(sdbusplus::message_t& msg)
 {
     if (msg.is_method_error())
diff --git a/src/webserver_run.cpp b/src/webserver_run.cpp
index eddfc5b..93bf6b5 100644
--- a/src/webserver_run.cpp
+++ b/src/webserver_run.cpp
@@ -78,10 +78,9 @@
     if constexpr (BMCWEB_REDFISH)
     {
         redfish::RedfishService redfish(app);
-        if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
-        {
-            redfish::EventServiceManager::getInstance(&*io);
-        }
+
+        // Create EventServiceManager instance and initialize Config
+        redfish::EventServiceManager::getInstance(&*io);
 
         if constexpr (BMCWEB_REDFISH_AGGREGATION)
         {