Implement Logging.Create interface

This adds the xyz.openbmc_project.Logging.Create interface on the
/xyz/openbmc_project/logging path.  The interface provides a single
method, Create, that allows one to create an event log.

This is an alternative to using the report/commit functions provided by
the phosphor-logging/elog.hpp header file.

Unlike those report/commit interfaces, this does not require that the
entries in the AdditionalData event log property be defined ahead of
time, as the whole AdditionalData contents are just passed in instead of
read out of the journal.  This means that the error does not need to
have been defined in the error and metadata YAML files for an event log
to be successfully created.  The discussion on if that is still desired
anyway is outside the scope of this commit.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Icf3f740ab86605deeaeb955ff51aa2ef292f5af4
diff --git a/elog_meta.hpp b/elog_meta.hpp
index fe14a11..6783a32 100644
--- a/elog_meta.hpp
+++ b/elog_meta.hpp
@@ -46,6 +46,23 @@
     }
 };
 
+/** @brief Combine the metadata keys and values from the map
+ *         into a vector of strings that look like:
+ *            "<metadata name>=<metadata value>"
+ *  @param [in] data - metadata key:value map
+ *  @param [out] metadata - vector of "key=value" strings
+ */
+inline void combine(const std::map<std::string, std::string>& data,
+                    std::vector<std::string>& metadata)
+{
+    for (const auto& [key, value] : data)
+    {
+        std::string line{key};
+        line += "=" + value;
+        metadata.push_back(std::move(line));
+    }
+}
+
 /** @brief Build error associations specific to metadata. Specialize this
  *         template for handling a specific type of metadata.
  *  @tparam M - type of metadata
diff --git a/log_manager.cpp b/log_manager.cpp
index 2920546..2acbfad 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -562,6 +562,16 @@
     return version;
 }
 
+void Manager::create(const std::string& message, Entry::Level severity,
+                     const std::map<std::string, std::string>& additionalData)
+{
+    // Convert the map into a vector of "key=value" strings
+    std::vector<std::string> ad;
+    metadata::associations::combine(additionalData, ad);
+
+    createEntry(message, severity, ad);
+}
+
 } // namespace internal
 } // namespace logging
 } // namespace phosphor
diff --git a/log_manager.hpp b/log_manager.hpp
index 15dd3af..c5ae081 100644
--- a/log_manager.hpp
+++ b/log_manager.hpp
@@ -2,6 +2,8 @@
 
 #include "elog_entry.hpp"
 #include "xyz/openbmc_project/Collection/DeleteAll/server.hpp"
+#include "xyz/openbmc_project/Logging/Create/server.hpp"
+#include "xyz/openbmc_project/Logging/Entry/server.hpp"
 #include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp"
 
 #include <list>
@@ -16,14 +18,14 @@
 extern const std::map<std::string, std::vector<std::string>> g_errMetaMap;
 extern const std::map<std::string, level> g_errLevelMap;
 
-using DeleteAllIface = sdbusplus::server::object::object<
-    sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>;
+using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create;
+using DeleteAllIface =
+    sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;
 
 namespace details
 {
-
-template <typename T>
-using ServerObject = typename sdbusplus::server::object::object<T>;
+template <typename... T>
+using ServerObject = typename sdbusplus::server::object::object<T...>;
 
 using ManagerIface =
     sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;
@@ -124,6 +126,21 @@
         return busLog;
     }
 
+    /** @brief Creates an event log
+     *
+     *  This is an alternative to the _commit() API.  It doesn't use
+     *  the journal to look up event log metadata like _commit does.
+     *
+     * @param[in] errMsg - The error exception message associated with the
+     *                     error log to be committed.
+     * @param[in] severity - level of the error
+     * @param[in] additionalData - The AdditionalData property for the error
+     */
+    void create(
+        const std::string& message,
+        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
+        const std::map<std::string, std::string>& additionalData);
+
   private:
     /*
      * @fn _commit()
@@ -199,11 +216,13 @@
 } // namespace internal
 
 /** @class Manager
- *  @brief Implementation for delete all error log entries.
+ *  @brief Implementation for deleting all error log entries and
+ *         creating new logs.
  *  @details A concrete implementation for the
- *  xyz.openbmc_project.Collection.DeleteAll
+ *           xyz.openbmc_project.Collection.DeleteAll and
+ *           xyz.openbmc_project.Logging.Create interfaces.
  */
-class Manager : public DeleteAllIface
+class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
 {
   public:
     Manager() = delete;
@@ -222,7 +241,8 @@
      */
     Manager(sdbusplus::bus::bus& bus, const std::string& path,
             internal::Manager& manager) :
-        DeleteAllIface(bus, path.c_str(), true),
+        details::ServerObject<DeleteAllIface, CreateIface>(bus, path.c_str(),
+                                                           true),
         manager(manager){};
 
     /** @brief Delete all d-bus objects.
@@ -232,6 +252,21 @@
         manager.eraseAll();
     }
 
+    /** @brief D-Bus method call implementation to create an event log.
+     *
+     * @param[in] errMsg - The error exception message associated with the
+     *                     error log to be committed.
+     * @param[in] severity - Level of the error
+     * @param[in] additionalData - The AdditionalData property for the error
+     */
+    void create(
+        std::string message,
+        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
+        std::map<std::string, std::string> additionalData) override
+    {
+        manager.create(message, severity, additionalData);
+    }
+
   private:
     /** @brief This is a reference to manager object */
     internal::Manager& manager;