log_manager: Use sdbus++

Change-Id: Id2ad6a75b6ee3f7226c7cfd274dba24de89f9363
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index ac50cc9..f96d2cf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,12 @@
 bin_PROGRAMS = logging-test
 logging_test_SOURCES = logging_test.cpp
 
+sbin_PROGRAMS = phosphor-log-manager
+phosphor_log_manager_SOURCES = \
+	xyz.openbmc_project.Logging.Internal.Manager.cpp \
+	log_manager.cpp \
+	log_manager_main.cpp
+
 # Be sure to build elog-gen.hpp before compiling
 BUILT_SOURCES = elog-gen.hpp
 
@@ -15,6 +21,7 @@
 
 # systemd required for journal interfaces
 logging_test_LDFLAGS = $(SYSTEMD_LIBS)
+phosphor_log_manager_LDFLAGS = $(SYSTEMD_LIBS)
 
 ELOG_YAML ?= xyz/openbmc_project/Example/Elog.errors.yaml
 ELOG_MAKO ?= elog-gen-template.mako.hpp
diff --git a/configure.ac b/configure.ac
index 7f8a446..8ed1a3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,9 @@
 
 AC_CHECK_HEADER(systemd/sd-journal.h, ,[AC_MSG_ERROR([Could not find \
 systemd/sd-journal.h...systemd developement package required])])
+AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find \
+systemd/sd-bus.h...systemd developement package required])])
+
 
 # Check/set gtest specific functions.
 AX_PTHREAD([GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=1"],[GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=0"])
@@ -43,6 +46,8 @@
     AC_SUBST([OESDK_TESTCASE_FLAGS], [$testcase_flags])
 )
 
+AC_DEFINE(BUSNAME, "xyz.openbmc_project.Logging.Internal.Manager", [The DBus busname to own.])
+AC_DEFINE(OBJ, "/xyz/openbmc_project/Logging/Internal", [The DBus object path.])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([Makefile test/Makefile])
-AC_OUTPUT
\ No newline at end of file
+AC_OUTPUT
diff --git a/log_manager.cpp b/log_manager.cpp
index 21e99a8..a3e49e9 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -7,65 +7,38 @@
 #include <systemd/sd-bus.h>
 #include <systemd/sd-journal.h>
 #include "log.hpp"
+#include "log_manager.hpp"
 
-using namespace phosphor;
+namespace phosphor
+{
+namespace logging
+{
 
-/*
- * @fn commit()
- * @brief Create an error/event log based on specified id and metadata variable
- *        names that includes the journal message and the metadata values.
- */
-auto commit(sd_bus_message *msg, void *userdata, sd_bus_error *error)
+void Manager::commit(uint64_t transactionId, std::string errMsg)
 {
     // TODO Change /tmp path to a permanent location on flash
     constexpr const auto path = "/tmp/elog";
     constexpr const auto msgIdStr = "_PID";
 
-    // Read PID
-    int rc = -1;
-    char *msgId = nullptr;
-    rc = sd_bus_message_read(msg, "s", &msgId);
-    if (rc < 0)
-    {
-        logging::log<logging::level::ERR>("Failed to read msg id",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        return sd_bus_reply_method_return(msg, "i", rc);
-    }
-
     // Create log file
     std::string filename{};
     filename.append(path);
     // TODO Create error logs in their own separate dir once permanent location
-    // on flash is determined. Ex: ../msgId/1
-    filename.append(msgId);
+    // on flash is determined. Ex: ../transactionId/1
     std::ofstream efile;
     efile.open(filename);
     efile << "{" << std::endl;
 
-    // Read metadata variables passed as array of strings and store in vector
-    // TODO Read required metadata fields from header file instead
-    rc = sd_bus_message_enter_container(msg, SD_BUS_TYPE_ARRAY, "s");
-    if (rc < 0)
-    {
-        logging::log<logging::level::ERR>("Failed to read metadata vars",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        return sd_bus_reply_method_return(msg, nullptr);
-    }
-    const char* metaVar = nullptr;
+    //const char* metaVar = nullptr;
     std::vector<const char*> metaList;
-    while ((rc = sd_bus_message_read_basic(msg, 's', &metaVar)) > 0)
-    {
-        metaList.push_back(metaVar);
-    }
-    sd_bus_message_exit_container(msg);
 
     sd_journal *j = nullptr;
-    rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
+    int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
     if (rc < 0)
     {
         logging::log<logging::level::ERR>("Failed to open journal",
                            logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        return sd_bus_reply_method_return(msg, nullptr);
+        return;
     }
 
     // Read the journal from the end to get the most recent entry first.
@@ -83,12 +56,16 @@
             continue;
         }
         std::string result(data);
-        if (result.find(msgId) == std::string::npos)
+// TODO String msgid is now an int transaction id. This piece will be
+// uncommented and reworked with the upcoming change to read the metadata
+// fields from the header file.
+#if 0
+        if (result.find(msgid) == std::string::npos)
         {
             // Match not found, continue to next journal entry
             continue;
         }
-
+#endif
         // Match found, write to file
         // TODO This is a draft format based on the redfish event logs written
         // in json, the final openbmc format is to be determined
@@ -128,87 +105,34 @@
 
     efile << "}" << std::endl;
     efile.close();
-    return sd_bus_reply_method_return(msg, nullptr);
+    return;
 }
 
-constexpr sdbusplus::vtable::vtable_t log_vtable[] =
+Manager::Manager(sdbusplus::bus::bus &&bus,
+                 const char* busname,
+                 const char* obj) :
+    details::ServerObject<details::ManagerIface>(bus, obj),
+    _bus(std::move(bus)),
+    _manager(sdbusplus::server::manager::manager(_bus, obj))
 {
-    sdbusplus::vtable::start(),
-    sdbusplus::vtable::method("Commit", "sas", "", commit),
-    sdbusplus::vtable::end()
-};
+    _bus.request_name(busname);
+}
 
-int main(int argc, char *argv[])
+void Manager::run() noexcept
 {
-    constexpr const auto dbusLogObj = "/xyz/openbmc_project/Logging";
-    constexpr const auto dbusLogName = "xyz.openbmc_project.Logging";
-    int rc = -1;
-    sd_bus *bus = nullptr;
-
-    rc = sd_bus_open_system(&bus);
-    if (rc < 0)
+    while(true)
     {
-        logging::log<logging::level::ERR>("Failed to open system bus",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        goto cleanup;
-    }
-
-    rc = sd_bus_add_object_manager(bus, nullptr, dbusLogObj);
-    if (rc < 0)
-    {
-        logging::log<logging::level::ERR>("Failed to add object mgr",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        goto cleanup;
-    }
-
-    rc = sd_bus_add_object_vtable(bus,
-                                  nullptr,
-                                  dbusLogObj,
-                                  dbusLogName,
-                                  log_vtable,
-                                  nullptr);
-    if (rc < 0)
-    {
-        logging::log<logging::level::ERR>("Failed to add vtable",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-        goto cleanup;
-    }
-
-    rc = sd_bus_request_name(bus, dbusLogName, 0);
-    if (rc < 0)
-    {
-        logging::log<logging::level::ERR>("Failed to acquire service name",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-    }
-    else
-    {
-        for(;;)
+        try
         {
-            rc = sd_bus_process(bus, nullptr);
-            if (rc < 0)
-            {
-                logging::log<logging::level::ERR>("Failed to connect to bus",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-                break;
-            }
-            if (rc > 0)
-            {
-                continue;
-            }
-
-            rc = sd_bus_wait(bus, (uint64_t) - 1);
-            if (rc < 0)
-            {
-                logging::log<logging::level::ERR>("Failed to wait on bus",
-                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
-                break;
-            }
+            _bus.process_discard();
+            _bus.wait();
+        }
+        catch (std::exception &e)
+        {
+            std::cerr << e.what() << std::endl;
         }
     }
-
-cleanup:
-    sd_bus_unref(bus);
-
-    return rc;
 }
 
+} // namespace logging
+} // namepsace phosphor
diff --git a/log_manager.hpp b/log_manager.hpp
new file mode 100644
index 0000000..2b4281d
--- /dev/null
+++ b/log_manager.hpp
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <sdbusplus/server.hpp>
+#include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp"
+
+namespace phosphor
+{
+namespace logging
+{
+namespace details
+{
+
+template <typename T>
+using ServerObject = typename sdbusplus::server::object::object<T>;
+
+using ManagerIface =
+    sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;
+
+} // namespace details
+
+/** @class Manager
+ *  @brief OpenBMC logging manager implementation.
+ *  @details A concrete implementation for the
+ *  xyz.openbmc_project.Logging.Internal.Manager DBus API.
+ */
+class Manager final :
+    public details::ServerObject<details::ManagerIface>
+{
+    public:
+        Manager() = delete;
+        Manager(const Manager&) = delete;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = default;
+        Manager& operator=(Manager&&) = default;
+        ~Manager() = default;
+
+        /** @brief Constructor for the Log Manager object
+         *  @param[in] bus - DBus bus to attach to.
+         *  @param[in] busname - Name of DBus bus to own.
+         *  @param[in] obj - Object path to attach to.
+         */
+        Manager(sdbusplus::bus::bus&& bus,
+                    const char* busname,
+                    const char* obj);
+
+        /** @brief Start processing DBus messages. */
+        void run() noexcept;
+
+        /*
+         * @fn commit()
+         * @brief sd_bus Commit method implementation callback.
+         * @details Create an error/event log based on transaction id and
+         *          error message.
+         * @param[in] transactionId - Unique identifier of the journal entries
+         *                            to be committed.
+         * @param[in] errMsg - The error exception message associated with the
+         *                     error log to be committed.
+         */
+        void commit(uint64_t transactionId, std::string errMsg) override;
+
+    private:
+        /** @brief Persistent sdbusplus DBus bus connection. */
+        sdbusplus::bus::bus _bus;
+
+        /** @brief sdbusplus org.freedesktop.DBus.ObjectManager reference. */
+        sdbusplus::server::manager::manager _manager;
+};
+
+} // namespace logging
+} // namespace phosphor
diff --git a/log_manager_main.cpp b/log_manager_main.cpp
new file mode 100644
index 0000000..21c13ae
--- /dev/null
+++ b/log_manager_main.cpp
@@ -0,0 +1,22 @@
+#include "config.h"
+#include "log_manager.hpp"
+#include <sdbusplus/bus.hpp>
+#include <cstdlib>
+#include <iostream>
+#include <exception>
+
+int main(int argc, char *argv[])
+{
+    try {
+        auto manager = phosphor::logging::Manager(
+                sdbusplus::bus::new_system(),
+                BUSNAME,
+                OBJ);
+        manager.run();
+        exit(EXIT_SUCCESS);
+    }
+    catch (const std::exception &e) {
+        std::cerr << e.what() << std::endl;
+    }
+    exit(EXIT_FAILURE);
+}
diff --git a/xyz.openbmc_project.Logging.Internal.Manager.cpp b/xyz.openbmc_project.Logging.Internal.Manager.cpp
new file mode 100644
index 0000000..2afdb6d
--- /dev/null
+++ b/xyz.openbmc_project.Logging.Internal.Manager.cpp
@@ -0,0 +1,91 @@
+#include <algorithm>
+#include <sdbusplus/server.hpp>
+#include <sdbusplus/exception.hpp>
+#include <xyz/openbmc_project/Logging/Internal/Manager/server.hpp>
+
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Logging
+{
+namespace Internal
+{
+namespace server
+{
+
+Manager::Manager(bus::bus& bus, const char* path)
+        : _xyz_openbmc_project_Logging_Internal_Manager_interface(
+                bus, path, _interface, _vtable, this)
+{
+}
+
+
+int Manager::_callback_Commit(
+        sd_bus_message* msg, void* context, sd_bus_error* error)
+{
+    using sdbusplus::server::binding::details::convertForMessage;
+
+    try
+    {
+        auto m = message::message(sd_bus_message_ref(msg));
+
+        uint64_t transactionId{};
+    std::string errMsg{};
+
+        m.read(transactionId, errMsg);
+
+        auto o = static_cast<Manager*>(context);
+        o->commit(transactionId, errMsg);
+
+        auto reply = m.new_method_return();
+        // No data to append on reply.
+
+        reply.method_return();
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+namespace details
+{
+namespace Manager
+{
+static const auto _param_Commit =
+        utility::tuple_to_array(message::types::type_id<
+                uint64_t, std::string>());
+static const auto _return_Commit =
+        utility::tuple_to_array(std::make_tuple('\0'));
+}
+}
+
+
+
+
+const vtable::vtable_t Manager::_vtable[] = {
+    vtable::start(),
+
+    vtable::method("Commit",
+                   details::Manager::_param_Commit
+                        .data(),
+                   details::Manager::_return_Commit
+                        .data(),
+                   _callback_Commit),
+    vtable::end()
+};
+
+} // namespace server
+} // namespace Internal
+} // namespace Logging
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
diff --git a/xyz/openbmc_project/Logging/Internal/Manager/server.hpp b/xyz/openbmc_project/Logging/Internal/Manager/server.hpp
new file mode 100644
index 0000000..3bec2a9
--- /dev/null
+++ b/xyz/openbmc_project/Logging/Internal/Manager/server.hpp
@@ -0,0 +1,81 @@
+#pragma once
+#include <tuple>
+#include <systemd/sd-bus.h>
+#include <sdbusplus/server.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Logging
+{
+namespace Internal
+{
+namespace server
+{
+
+class Manager
+{
+    public:
+        /* Define all of the basic class operations:
+         *     Not allowed:
+         *         - Default constructor to avoid nullptrs.
+         *         - Copy operations due to internal unique_ptr.
+         *     Allowed:
+         *         - Move operations.
+         *         - Destructor.
+         */
+        Manager() = delete;
+        Manager(const Manager&) = delete;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = default;
+        Manager& operator=(Manager&&) = default;
+        virtual ~Manager() = default;
+
+        /** @brief Constructor to put object onto bus at a dbus path.
+         *  @param[in] bus - Bus to attach to.
+         *  @param[in] path - Path to attach at.
+         */
+        Manager(bus::bus& bus, const char* path);
+
+
+
+        /** @brief Implementation for Commit
+         *  Write the requested error/event entry with its associated metadata fields to flash.
+         *
+         *  @param[in] transactionId - The unique identifier of the journal entry(ies) to be committed.
+         *  @param[in] errMsg - The error exception message associated with the error event log to be committed.
+         */
+        virtual void commit(
+            uint64_t transactionId,
+            std::string errMsg) = 0;
+
+
+
+
+    private:
+
+        /** @brief sd-bus callback for Commit
+         */
+        static int _callback_Commit(
+            sd_bus_message*, void*, sd_bus_error*);
+
+
+        static constexpr auto _interface = "xyz.openbmc_project.Logging.Internal.Manager";
+        static const vtable::vtable_t _vtable[];
+        sdbusplus::server::interface::interface
+                _xyz_openbmc_project_Logging_Internal_Manager_interface;
+
+
+};
+
+
+} // namespace server
+} // namespace Internal
+} // namespace Logging
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+