Implement ability to override default error level

Errors reported by the phosphor-logging app have a default error level,
and this level is specified in the error's YAML definition.

Enable users of the error's report() API to specify an error level. A
user may perceive a different error level for an error scenario, for eg
there may be certain host errors (for which we set the level as 'Error')
that may just be 'Warnings'.

Change-Id: I666a0ddcb099e530c423358a3b1c65f33b0ad01e
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/elog.cpp b/elog.cpp
index 27dfef5..363553b 100644
--- a/elog.cpp
+++ b/elog.cpp
@@ -1,5 +1,6 @@
 #include "config.h"
 #include <phosphor-logging/elog.hpp>
+#include <stdexcept>
 
 namespace phosphor
 {
@@ -7,7 +8,9 @@
 {
 namespace details
 {
-void commit(const char* name)
+using namespace sdbusplus::xyz::openbmc_project::Logging::server;
+
+auto _prepareMsg(const char* funcName)
 {
     using phosphor::logging::log;
     constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
@@ -29,16 +32,14 @@
     auto mapperResponseMsg = b.call(mapper);
     if (mapperResponseMsg.is_method_error())
     {
-        log<level::ERR>("Error in mapper call");
-        return;
+        throw std::runtime_error("Error in mapper call");
     }
 
     std::map<std::string, std::vector<std::string>> mapperResponse;
     mapperResponseMsg.read(mapperResponse);
     if (mapperResponse.empty())
     {
-        log<level::ERR>("Error reading mapper response");
-        return;
+        throw std::runtime_error("Error reading mapper response");
     }
 
     const auto& host = mapperResponse.cbegin()->first;
@@ -46,10 +47,26 @@
             host.c_str(),
             OBJ_INTERNAL,
             IFACE_INTERNAL,
-            "Commit");
+            funcName);
+   return m;
+}
+
+void commit(const char* name)
+{
+    auto msg = _prepareMsg("Commit");
     uint64_t id = sdbusplus::server::transaction::get_id();
-    m.append(id, name);
-    b.call_noreply(m);
+    msg.append(id, name);
+    auto bus = sdbusplus::bus::new_default();
+    bus.call_noreply(msg);
+}
+
+void commit(const char* name, Entry::Level level)
+{
+    auto msg = _prepareMsg("CommitWithLvl");
+    uint64_t id = sdbusplus::server::transaction::get_id();
+    msg.append(id, name, static_cast<uint32_t>(level));
+    auto bus = sdbusplus::bus::new_default();
+    bus.call_noreply(msg);
 }
 } // namespace details
 
diff --git a/log_manager.cpp b/log_manager.cpp
index cc5e187..92454fe 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -25,17 +25,37 @@
 {
 namespace internal
 {
-void Manager::commit(uint64_t transactionId, std::string errMsg)
-{
-    auto reqLevel = level::ERR; // Default to ERR
-    auto levelmap = g_errLevelMap.find(errMsg);
 
+inline auto getLevel(const std::string& errMsg)
+{
+    auto reqLevel = Entry::Level::Error; // Default to Error
+
+    auto levelmap = g_errLevelMap.find(errMsg);
     if (levelmap != g_errLevelMap.end())
     {
-        reqLevel = levelmap->second;
+        reqLevel = static_cast<Entry::Level>(levelmap->second);
     }
 
-    if (static_cast<Entry::Level>(reqLevel) < Entry::sevLowerLimit)
+    return reqLevel;
+}
+
+void Manager::commit(uint64_t transactionId, std::string errMsg)
+{
+    auto level = getLevel(errMsg);
+    _commit(transactionId, std::move(errMsg), level);
+}
+
+void Manager::commitWithLvl(uint64_t transactionId, std::string errMsg,
+                            uint32_t errLvl)
+{
+    _commit(transactionId, std::move(errMsg),
+            static_cast<Entry::Level>(errLvl));
+}
+
+void Manager::_commit(uint64_t transactionId, std::string&& errMsg,
+                      Entry::Level errLvl)
+{
+    if (errLvl < Entry::sevLowerLimit)
     {
         if (realErrors.size() >= ERROR_CAP)
         {
@@ -158,7 +178,7 @@
 
     // Create error Entry dbus object
     entryId++;
-    if (static_cast<Entry::Level>(reqLevel) >= Entry::sevLowerLimit)
+    if (errLvl >= Entry::sevLowerLimit)
     {
         infoErrors.push_back(entryId);
     }
@@ -179,7 +199,7 @@
                  objPath,
                  entryId,
                  ms, // Milliseconds since 1970
-                 static_cast<Entry::Level>(reqLevel),
+                 errLvl,
                  std::move(errMsg),
                  std::move(additionalData),
                  std::move(objects),
diff --git a/log_manager.hpp b/log_manager.hpp
index b165ff3..9339a6f 100644
--- a/log_manager.hpp
+++ b/log_manager.hpp
@@ -68,6 +68,19 @@
          */
         void commit(uint64_t transactionId, std::string errMsg) override;
 
+        /*
+         * @fn commit()
+         * @brief sd_bus CommitWithLvl 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.
+         * @param[in] errLvl - level of the error
+         */
+        void commitWithLvl(uint64_t transactionId, std::string errMsg,
+                           uint32_t errLvl) override;
 
         /** @brief Erase specified entry d-bus object
          *
@@ -95,6 +108,18 @@
         }
 
     private:
+        /*
+         * @fn _commit()
+         * @brief commit() helper
+         * @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.
+         * @param[in] errLvl - level of the error
+         */
+        void _commit(uint64_t transactionId, std::string&& errMsg,
+                     Entry::Level errLvl);
+
         /** @brief Call metadata handler(s), if any. Handlers may create
          *         associations.
          *  @param[in] errorName - name of the error
diff --git a/phosphor-logging/elog.hpp b/phosphor-logging/elog.hpp
index 8a6b9c1..b76bd6c 100644
--- a/phosphor-logging/elog.hpp
+++ b/phosphor-logging/elog.hpp
@@ -3,12 +3,16 @@
 #include <utility>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/exception.hpp>
+#include "xyz/openbmc_project/Logging/Entry/server.hpp"
+
 namespace phosphor
 {
 
 namespace logging
 {
 
+using namespace sdbusplus::xyz::openbmc_project::Logging::server;
+
 /**
  * @brief Structure used by callers to indicate they want to use the last value
  *        put in the journal for input parameter.
@@ -90,6 +94,10 @@
  */
 void commit(const char* name);
 
+/** @fn commit() - override that accepts error level
+ */
+void commit(const char* name, Entry::Level level);
+
 } // namespace details
 
 /** @fn commit()
@@ -115,6 +123,22 @@
     details::commit(T::errName);
 }
 
+/** @fn commit()
+ *  @brief Create an error log entry based on journal
+ *         entry with a specified MSG_ID. This override accepts error level.
+ *  @param[in] level - level of the error
+ */
+template <typename T>
+void commit(Entry::Level level)
+{
+    // Validate if the exception is derived from sdbusplus::exception.
+    static_assert(
+        std::is_base_of<sdbusplus::exception::exception, T>::value,
+        "T must be a descendant of sdbusplus::exception::exception"
+    );
+    details::commit(T::errName, level);
+}
+
 
 /** @fn elog()
  *  @brief Create a journal log entry based on predefined
@@ -176,6 +200,39 @@
 
     commit<T>();
 }
+
+/** @fn report()
+ *  @brief Create a journal log entry based on predefined
+ *         error log information and commit the error. Accepts error
+ *         level.
+ *  @tparam T - exception
+ *  @param[in] level - level of the error
+ *  @param[in] i_args - Metadata fields to be added to the journal entry
+ */
+template <typename T, typename ...Args>
+void report(Entry::Level level, Args... i_args)
+{
+    //validate if the exception is derived from sdbusplus::exception.
+    static_assert(
+        std::is_base_of<sdbusplus::exception::exception, T>::value,
+        "T must be a descendant of sdbusplus::exception::exception"
+    );
+
+    // Validate the caller passed in the required parameters
+    static_assert(std::is_same<typename details::
+                               map_exception_type_t<T>::metadata_types,
+                               std::tuple<
+                               details::deduce_entry_type_t<Args>...>>
+                               ::value,
+                  "You are not passing in required arguments for this error");
+
+    log<details::map_exception_type_t<T>::L>(
+        T::errDesc,
+        details::deduce_entry_type<Args>{i_args}.get()...);
+
+    commit<T>(level);
+}
+
 } // namespace logging
 
 } // namespace phosphor
diff --git a/xyz/openbmc_project/Logging/Internal/Manager.interface.yaml b/xyz/openbmc_project/Logging/Internal/Manager.interface.yaml
index 97ed3c9..4c1c8ce 100644
--- a/xyz/openbmc_project/Logging/Internal/Manager.interface.yaml
+++ b/xyz/openbmc_project/Logging/Internal/Manager.interface.yaml
@@ -6,7 +6,8 @@
     - name: Commit
       description: >
           Write the requested error/event entry with its associated metadata
-          fields to flash.
+          fields to flash. The "level" of the committed error log is same as the
+          level defined in error YAML definitions.
       parameters:
         - name: transactionId
           type: uint64
@@ -17,3 +18,22 @@
           description: >
               The error exception message associated with the error
               event log to be committed.
+    - name: CommitWithLvl
+      description: >
+          Write the requested error/event entry with its associated metadata
+          fields to flash. This interface allows the caller to override the
+          error level specified in the error YAML definition.
+      parameters:
+        - name: transactionId
+          type: uint64
+          description: >
+              The unique identifier of the journal entry(ies) to be committed.
+        - name: errMsg
+          type: string
+          description: >
+              The error exception message associated with the error
+              event log to be committed.
+        - name: errLvl
+          type: uint32
+          description: >
+              The error level/severity indicator.