Implement led assert and deassert based on faults

Change-Id: I28378b155da15282b1b5bf0403075b55bda5b70d
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index c0fc04a..ba1a152 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,6 +45,10 @@
 PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],, [AC_MSG_ERROR([Could not find phosphor-logging...openbmc/phosphor-logging package required])])
 PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces],, [AC_MSG_ERROR([Could not find phosphor-dbus-interfaces...openbmc/phosphor-dbus-interfaces package required])])
 
+# Check for sdbus++ tool
+AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++])
+AS_IF([test "x$SDBUSPLUSPLUS" == "x"], AC_MSG_ERROR([Cannot find sdbus++]))
+
 # Dbus service name
 AC_ARG_VAR(BUSNAME, [The Dbus busname to own])
 AS_IF([test "x$BUSNAME" == "x"], [BUSNAME="xyz.openbmc_project.LED.GroupManager"])
@@ -63,6 +67,8 @@
 
 AC_DEFINE(CALLOUT_FWD_ASSOCIATION, "callout", [The name of the callout's forward association.])
 AC_DEFINE(CALLOUT_REV_ASSOCIATION, "fault", [The name of the callout's reverse association.])
+AC_DEFINE(ELOG_ENTRY, "entry", [Path element indicates an error log entry under logging namespace.])
+AC_DEFINE(LED_FAULT, "fault", [Path element to indicates a fault led under led groups.])
 
 # Create configured output
 AC_CONFIG_FILES([Makefile test/Makefile fault-monitor/Makefile])
diff --git a/elog-errors.hpp b/elog-errors.hpp
new file mode 100644
index 0000000..1cc6f4a
--- /dev/null
+++ b/elog-errors.hpp
@@ -0,0 +1,402 @@
+// This file was autogenerated.  Do not edit!
+// See elog-gen.py for more details
+#pragma once
+
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <sdbusplus/exception.hpp>
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace Error
+{
+    struct AssociationRetrieveError;
+} // namespace Error
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace Error
+{
+    struct InventoryPathError;
+} // namespace Error
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace Error
+{
+    struct ObjectNotFoundError;
+} // namespace Error
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace Error
+{
+    struct MethodError;
+} // namespace Error
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+
+namespace phosphor
+{
+
+namespace logging
+{
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace _InventoryPathError
+{
+
+struct PATH
+{
+    static constexpr auto str = "PATH=%s";
+    static constexpr auto str_short = "PATH";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+
+}  // namespace _InventoryPathError
+
+struct InventoryPathError : public sdbusplus::exception_t
+{
+    static constexpr auto errName = "xyz.openbmc_project.Led.Fru.Monitor.InventoryPathError";
+    static constexpr auto errDesc = "Invalid Inventory Path.";
+    static constexpr auto L = level::INFO;
+    using PATH = _InventoryPathError::PATH;
+    using metadata_types = std::tuple<PATH>;
+
+    const char* name() const noexcept
+    {
+        return errName;
+    }
+
+    const char* description() const noexcept
+    {
+        return errDesc;
+    }
+
+    const char* what() const noexcept
+    {
+        return errName;
+    }
+};
+
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Fru::Monitor::Error::InventoryPathError>
+{
+    using type = xyz::openbmc_project::Led::Fru::Monitor::InventoryPathError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace _AssociationRetrieveError
+{
+
+struct ELOG_ENTRY_PATH
+{
+    static constexpr auto str = "ELOG_ENTRY_PATH=%s";
+    static constexpr auto str_short = "ELOG_ENTRY_PATH";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr ELOG_ENTRY_PATH(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+
+}  // namespace _AssociationRetrieveError
+
+struct AssociationRetrieveError : public sdbusplus::exception_t
+{
+    static constexpr auto errName = "xyz.openbmc_project.Led.Fru.Monitor.AssociationRetrieveError";
+    static constexpr auto errDesc = "Error in retrieving the associations from elog entry.";
+    static constexpr auto L = level::INFO;
+    using ELOG_ENTRY_PATH = _AssociationRetrieveError::ELOG_ENTRY_PATH;
+    using metadata_types = std::tuple<ELOG_ENTRY_PATH>;
+
+    const char* name() const noexcept
+    {
+        return errName;
+    }
+
+    const char* description() const noexcept
+    {
+        return errDesc;
+    }
+
+    const char* what() const noexcept
+    {
+        return errName;
+    }
+};
+
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Fru::Monitor::Error::AssociationRetrieveError>
+{
+    using type = xyz::openbmc_project::Led::Fru::Monitor::AssociationRetrieveError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace _MethodError
+{
+
+struct METHOD_NAME
+{
+    static constexpr auto str = "METHOD_NAME=%s";
+    static constexpr auto str_short = "METHOD_NAME";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr METHOD_NAME(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+struct PATH
+{
+    static constexpr auto str = "PATH=%s";
+    static constexpr auto str_short = "PATH";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+struct INTERFACE
+{
+    static constexpr auto str = "INTERFACE=%s";
+    static constexpr auto str_short = "INTERFACE";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr INTERFACE(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+
+}  // namespace _MethodError
+
+struct MethodError : public sdbusplus::exception_t
+{
+    static constexpr auto errName = "xyz.openbmc_project.Led.Mapper.MethodError";
+    static constexpr auto errDesc = "Failed to invoke ObjectMapper method";
+    static constexpr auto L = level::INFO;
+    using METHOD_NAME = _MethodError::METHOD_NAME;
+    using PATH = _MethodError::PATH;
+    using INTERFACE = _MethodError::INTERFACE;
+    using metadata_types = std::tuple<METHOD_NAME, PATH, INTERFACE>;
+
+    const char* name() const noexcept
+    {
+        return errName;
+    }
+
+    const char* description() const noexcept
+    {
+        return errDesc;
+    }
+
+    const char* what() const noexcept
+    {
+        return errName;
+    }
+};
+
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Mapper::Error::MethodError>
+{
+    using type = xyz::openbmc_project::Led::Mapper::MethodError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace _ObjectNotFoundError
+{
+
+struct METHOD_NAME
+{
+    static constexpr auto str = "METHOD_NAME=%s";
+    static constexpr auto str_short = "METHOD_NAME";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr METHOD_NAME(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+struct PATH
+{
+    static constexpr auto str = "PATH=%s";
+    static constexpr auto str_short = "PATH";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+struct INTERFACE
+{
+    static constexpr auto str = "INTERFACE=%s";
+    static constexpr auto str_short = "INTERFACE";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr INTERFACE(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
+
+}  // namespace _ObjectNotFoundError
+
+struct ObjectNotFoundError : public sdbusplus::exception_t
+{
+    static constexpr auto errName = "xyz.openbmc_project.Led.Mapper.ObjectNotFoundError";
+    static constexpr auto errDesc = "Failed to get response from the method.";
+    static constexpr auto L = level::INFO;
+    using METHOD_NAME = _ObjectNotFoundError::METHOD_NAME;
+    using PATH = _ObjectNotFoundError::PATH;
+    using INTERFACE = _ObjectNotFoundError::INTERFACE;
+    using metadata_types = std::tuple<METHOD_NAME, PATH, INTERFACE>;
+
+    const char* name() const noexcept
+    {
+        return errName;
+    }
+
+    const char* description() const noexcept
+    {
+        return errDesc;
+    }
+
+    const char* what() const noexcept
+    {
+        return errName;
+    }
+};
+
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Mapper::Error::ObjectNotFoundError>
+{
+    using type = xyz::openbmc_project::Led::Mapper::ObjectNotFoundError;
+};
+
+}
+
+
+} // namespace logging
+
+} // namespace phosphor
diff --git a/fault-monitor/Makefile.am b/fault-monitor/Makefile.am
index ba7603f..044b638 100644
--- a/fault-monitor/Makefile.am
+++ b/fault-monitor/Makefile.am
@@ -7,7 +7,16 @@
 
 phosphor_fru_fault_monitor_SOURCES = \
                fru-fault-monitor.cpp \
-               monitor-main.cpp
+               monitor-main.cpp \
+               xyz/openbmc_project/Led/Mapper/error.cpp \
+               xyz/openbmc_project/Led/Fru/Monitor/error.cpp
+
+BUILT_SOURCES =  xyz/openbmc_project/Led/Mapper/error.hpp \
+                 xyz/openbmc_project/Led/Mapper/error.cpp \
+                 xyz/openbmc_project/Led/Fru/Monitor/error.hpp \
+                 xyz/openbmc_project/Led/Fru/Monitor/error.cpp
+
+CLEANFILES = ${BUILT_SOURCES}
 
 phosphor_fru_fault_monitor_LDFLAGS = $(SDBUSPLUS_LIBS) \
                                      $(PHOSPHOR_LOGGING_LIBS) \
@@ -15,3 +24,19 @@
 phosphor_fru_fault_monitor_CFLAGS =  $(SDBUSPLUS_CFLAGS) \
                                      $(PHOSPHOR_LOGGING_CFLAGS) \
                                      $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+
+xyz/openbmc_project/Led/Mapper/error.hpp: ${top_srcdir}/xyz/openbmc_project/Led/Mapper.errors.yaml
+	@mkdir -p `dirname $@`
+	$(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-header xyz.openbmc_project.Led.Mapper > $@
+
+xyz/openbmc_project/Led/Mapper/error.cpp: ${top_srcdir}/xyz/openbmc_project/Led/Mapper.errors.yaml
+	@mkdir -p `dirname $@`
+	$(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-cpp xyz.openbmc_project.Led.Mapper > $@
+
+xyz/openbmc_project/Led/Fru/Monitor/error.hpp: ${top_srcdir}/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
+	@mkdir -p `dirname $@`
+	$(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-header xyz.openbmc_project.Led.Fru.Monitor > $@
+
+xyz/openbmc_project/Led/Fru/Monitor/error.cpp: ${top_srcdir}/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
+	@mkdir -p `dirname $@`
+	$(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-cpp xyz.openbmc_project.Led.Fru.Monitor > $@
diff --git a/fault-monitor/fru-fault-monitor.cpp b/fault-monitor/fru-fault-monitor.cpp
index 1213128..e21727b 100644
--- a/fault-monitor/fru-fault-monitor.cpp
+++ b/fault-monitor/fru-fault-monitor.cpp
@@ -1,4 +1,9 @@
+#include <phosphor-logging/elog.hpp>
+#include "xyz/openbmc_project/Led/Fru/Monitor/error.hpp"
+#include "xyz/openbmc_project/Led/Mapper/error.hpp"
+#include "elog-errors.hpp"
 #include "fru-fault-monitor.hpp"
+
 namespace phosphor
 {
 namespace led
@@ -10,10 +15,105 @@
 namespace monitor
 {
 
+using namespace phosphor::logging;
+
+constexpr auto MAPPER_BUSNAME   = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_OBJ_PATH  = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_IFACE     = "xyz.openbmc_project.ObjectMapper";
+constexpr auto OBJMGR_IFACE     = "org.freedesktop.DBus.ObjectManager";
+constexpr auto LED_GROUPS       = "/xyz/openbmc_project/led/groups/";
+constexpr auto LOG_PATH         = "/xyz/openbmc_project/logging";
+
+using AssociationList = std::vector<std::tuple<
+                        std::string, std::string, std::string>>;
+using MethodErr  =
+    sdbusplus::xyz::openbmc_project::Led::Mapper::Error::MethodError;
+using ObjectNotFoundErr =
+    sdbusplus::xyz::openbmc_project::Led::Mapper::Error::ObjectNotFoundError;
+using AssociationRetrieveErr =
+    sdbusplus::xyz::openbmc_project::
+    Led::Fru::Monitor::Error::AssociationRetrieveError;
+using InventoryPathErr =
+    sdbusplus::xyz::openbmc_project::
+    Led::Fru::Monitor::Error::InventoryPathError;
+
+std::string getService(sdbusplus::bus::bus& bus,
+                       const std::string& path)
+{
+    auto mapper = bus.new_method_call(MAPPER_BUSNAME,
+                                      MAPPER_OBJ_PATH,
+                                      MAPPER_IFACE, "GetObject");
+    mapper.append(path.c_str(), std::vector<std::string>({OBJMGR_IFACE}));
+    auto mapperResponseMsg = bus.call(mapper);
+    if (mapperResponseMsg.is_method_error())
+    {
+        using namespace xyz::openbmc_project::Led::Mapper;
+        elog<MethodErr>(
+            MethodError::METHOD_NAME("GetObject"),
+            MethodError::PATH(path.c_str()),
+            MethodError::INTERFACE(
+                OBJMGR_IFACE));
+    }
+
+    std::map<std::string, std::vector<std::string>> mapperResponse;
+    mapperResponseMsg.read(mapperResponse);
+    if (mapperResponse.empty())
+    {
+        using namespace xyz::openbmc_project::Led::Mapper;
+        elog<ObjectNotFoundErr>(
+            ObjectNotFoundError::METHOD_NAME("GetObject"),
+            ObjectNotFoundError::PATH(path.c_str()),
+            ObjectNotFoundError::INTERFACE(
+                OBJMGR_IFACE));
+    }
+
+    return mapperResponse.cbegin()->first;
+}
+
 void action(sdbusplus::bus::bus& bus,
-            const std::string& unit,
+            const std::string& path,
             bool assert)
 {
+    std::string service;
+    try
+    {
+        service = getService(bus, LED_GROUPS);
+    }
+    catch (MethodErr& e)
+    {
+        commit<MethodErr>();
+        return;
+    }
+    catch (ObjectNotFoundErr& e)
+    {
+        commit<ObjectNotFoundErr>();
+        return;
+    }
+
+    auto pos = path.rfind("/");
+    if (pos == std::string::npos)
+    {
+        using namespace xyz::openbmc_project::Led::Fru::Monitor;
+        report<InventoryPathErr>(
+            InventoryPathError::PATH(
+                path.c_str()));
+        return;
+    }
+    auto unit = path.substr(pos + 1);
+
+    std::string ledPath = LED_GROUPS +
+                          unit + '_' + LED_FAULT;
+
+    auto method =  bus.new_method_call(service.c_str(),
+                                       ledPath.c_str(),
+                                       "org.freedesktop.DBus.Properties",
+                                       "Set");
+    method.append("xyz.openbmc_project.Led.Group");
+    method.append("Asserted");
+
+    method.append(sdbusplus::message::variant<bool>(assert));
+    bus.call_noreply(method);
+
     return;
 }
 
@@ -21,6 +121,72 @@
                  void* data,
                  sd_bus_error* retError)
 {
+    auto m = sdbusplus::message::message(msg);
+    auto bus = m.get_bus();
+
+    sdbusplus::message::object_path obPath;
+    m.read(obPath);
+    std::string objectPath(std::move(obPath));
+
+    std::size_t found = objectPath.find(ELOG_ENTRY);
+    if (found == std::string::npos)
+    {
+        //Not a new error entry skip
+        return 0;
+    }
+
+    std::string service;
+    try
+    {
+        service = getService(bus, LOG_PATH);
+    }
+    catch (MethodErr& e)
+    {
+        commit<MethodErr>();
+        return 0;
+    }
+    catch (ObjectNotFoundErr& e)
+    {
+        commit<ObjectNotFoundErr>();
+        return 0;
+    }
+
+    auto method =  bus.new_method_call(service.c_str(), objectPath.c_str(),
+                                       "org.freedesktop.DBus.Properties",
+                                       "Get");
+
+    method.append("org.openbmc.Associations");
+    method.append("associations");
+    auto reply = bus.call(method);
+    if (reply.is_method_error())
+    {
+        using namespace xyz::openbmc_project::Led::Fru::Monitor;
+        report<AssociationRetrieveErr>(
+            AssociationRetrieveError::ELOG_ENTRY_PATH(
+                objectPath.c_str()));
+        return 0;
+    }
+
+    sdbusplus::message::variant<AssociationList> assoc;
+    reply.read(assoc);
+
+    auto assocs =
+        sdbusplus::message::variant_ns::get<AssociationList>(assoc);
+    if (assocs.empty())
+    {
+        //No associations skip
+        return 0;
+    }
+
+    for (const auto& item : assocs)
+    {
+        if (std::get<1>(item).compare(CALLOUT_REV_ASSOCIATION) == 0)
+        {
+            action(bus, std::get<2>(item), true);
+            static_cast<Add*>(data)->removeWatches.emplace_back(
+                std::make_unique<Remove>(bus, std::get<2>(item)));
+        }
+    }
     return 0;
 }
 
@@ -28,6 +194,34 @@
                     void* data,
                     sd_bus_error* retError)
 {
+    auto m = sdbusplus::message::message(msg);
+    auto bus = m.get_bus();
+    std::string assoc;
+    m.read(assoc);
+
+    if (assoc.compare("org.openbmc.Association"))
+    {
+        //Skip if not about association
+        return 0;
+    }
+
+    std::map<std::string, std::vector<std::string>> endPoints;
+    m.read(endPoints);
+    auto it = endPoints.find("endpoints");
+
+    if (it == endPoints.end())
+    {
+        //No end points,skip
+        return 0;
+    }
+
+    if (!((*it).second.empty()))
+    {
+        //Skip, end points are not empty
+        return 0;
+    }
+
+    action(bus, static_cast<Remove*>(data)->inventoryPath, false);
     return 0;
 }
 
diff --git a/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml b/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
new file mode 100644
index 0000000..bb77f45
--- /dev/null
+++ b/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
@@ -0,0 +1,7 @@
+#xyz.openbmc_project.Led.Fru.Monitor.InventoryPathError
+- name: InventoryPathError
+  description: Invalid Inventory Path.
+
+#xyz.openbmc_project.Led.Fru.Monitor.AssociationRetrieveError
+- name: AssociationRetrieveError
+  description: Error in retrieving the associations from elog entry.
diff --git a/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml b/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml
new file mode 100644
index 0000000..bd59e5f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml
@@ -0,0 +1,9 @@
+- name: InventoryPathError
+  meta:
+    - str: "PATH=%s"
+      type: string
+
+- name: AssociationRetrieveError
+  meta:
+    - str: "ELOG_ENTRY_PATH=%s"
+      type: string
diff --git a/xyz/openbmc_project/Led/Mapper.errors.yaml b/xyz/openbmc_project/Led/Mapper.errors.yaml
new file mode 100644
index 0000000..c1cbd0f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Mapper.errors.yaml
@@ -0,0 +1,9 @@
+#xyz.openbmc_project.Led.Mapper.MethodError
+- name: MethodError
+  description: Failed to invoke ObjectMapper method
+
+#xyz.openbmc_project.Led.Mapper.ObjectNotFoundError
+- name: ObjectNotFoundError
+  description: Failed to get response from the method.
+
+
diff --git a/xyz/openbmc_project/Led/Mapper.metadata.yaml b/xyz/openbmc_project/Led/Mapper.metadata.yaml
new file mode 100644
index 0000000..0eb5c7f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Mapper.metadata.yaml
@@ -0,0 +1,17 @@
+- name: MethodError
+  meta:
+    - str: "METHOD_NAME=%s"
+      type: string
+    - str: "PATH=%s"
+      type: string
+    - str: "INTERFACE=%s"
+      type: string
+
+- name: ObjectNotFoundError
+  meta:
+    - str: "METHOD_NAME=%s"
+      type: string
+    - str: "PATH=%s"
+      type: string
+    - str: "INTERFACE=%s"
+      type: string