Add support for metadata

Added support for metadata in elog.hpp, elog mako file, and pdmgen.
This metadata will be added with the error log.

Change-Id: Iaf0fe24d71f6bdd02b51df208b2c1d66c68319d3
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/src/elog.hpp b/src/elog.hpp
index f138b0b..e4f5456 100644
--- a/src/elog.hpp
+++ b/src/elog.hpp
@@ -3,6 +3,7 @@
 #include <phosphor-logging/elog.hpp>
 #include "callback.hpp"
 #include <sdbusplus/exception.hpp>
+#include <experimental/tuple>
 
 namespace phosphor
 {
@@ -26,7 +27,7 @@
         ElogBase& operator=(ElogBase&&) = default;
         virtual ~ElogBase() = default;
         ElogBase() :
-            Callback(){}
+            Callback() {}
 
         /** @brief Callback interface implementation. */
         void operator()() override;
@@ -36,13 +37,35 @@
         virtual void log() const = 0;
 };
 
+namespace detail
+{
+
+/** @class CallElog
+ *  @brief Provide explicit call forwarding to phosphor::logging::report.
+ *
+ *  @tparam T - Error log type
+ *  @tparam Args - Metadata fields types.
+ */
+template <typename T, typename ...Args>
+struct CallElog
+{
+    static void op(Args&& ...args)
+    {
+        phosphor::logging::report<T>(std::forward<Args>(args)...);
+    }
+};
+
+} // namespace detail
 
 /** @class Elog
  *  @brief C++ type specific logic for the elog callback.
+ *         The elog callback logs the elog and elog metadata.
  *
  *  @tparam T - Error log type
+ *  @tparam Args - Metadata fields types.
+ *  @param[in] arguments - Metadata fields to be added to the error log
  */
-template <typename T>
+template <typename T, typename ...Args>
 class Elog : public ElogBase
 {
     public:
@@ -51,19 +74,34 @@
         Elog& operator=(const Elog&) = delete;
         Elog& operator=(Elog&&) = default;
         ~Elog() = default;
-        Elog() :
-            ElogBase() {}
+        Elog(Args&& ... arguments) :
+            ElogBase(), args(std::forward<Args>(arguments)...) {}
 
     private:
         /** @brief elog interface implementation. */
         void log() const override
         {
-
-            using namespace phosphor::logging;
-            report<T>();
+            std::experimental::apply(
+                detail::CallElog<T, Args...>::op,
+                std::tuple_cat(args));
         }
+        std::tuple<Args...> args;
+
 };
 
+/** @brief Argument type deduction for constructing Elog instances.
+ *
+ *  @tparam T - Error log type
+ *  @tparam Args - Metadata fields types.
+ *  @param[in] arguments - Metadata fields to be added to the error log
+ */
+template <typename T, typename ...Args>
+auto makeElog(Args&& ... arguments)
+{
+    return std::make_unique<Elog<T, Args...>>(
+               std::forward<Args>(arguments)...);
+}
+
 } // namespace monitoring
 } // namespace dbus
 } // namespace phosphor
diff --git a/src/pdmgen.py b/src/pdmgen.py
index dc2c704..3691d59 100755
--- a/src/pdmgen.py
+++ b/src/pdmgen.py
@@ -176,6 +176,23 @@
 
         return a
 
+class Metadata(Argument):
+    '''Metadata type arguments.'''
+
+    def __init__(self, **kw):
+        self.value = kw.pop('value')
+        self.decorators = kw.pop('decorators', [])
+        if kw.get('type', None) == 'string':
+            self.decorators.insert(0, Quote())
+
+        super(Metadata, self).__init__(**kw)
+
+    def argument(self, loader, indent):
+        a = str(self.value)
+        for d in self.decorators:
+            a = d(a)
+
+        return a
 
 class Indent(object):
     '''Help templates be depth agnostic.'''
@@ -665,10 +682,10 @@
 
     def __init__(self, *a, **kw):
         self.error = kw.pop('error')
+        self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
         super(Elog, self).__init__(**kw)
 
     def construct(self, loader, indent):
-
         with open('errors.hpp', 'a') as fd:
             fd.write(
                 self.render(
diff --git a/src/templates/elog.mako.cpp b/src/templates/elog.mako.cpp
index 894ecde..f105090 100644
--- a/src/templates/elog.mako.cpp
+++ b/src/templates/elog.mako.cpp
@@ -1 +1,3 @@
-std::make_unique<Elog<sdbusplus::${c.error}>>()\
+makeElog<sdbusplus::${c.error}>(
+${indent(1)}${(',\n' + indent(1)).join(["phosphor::logging::" + meta.name + '(' +
+meta.argument(loader, indent=indent +1) + ')' for meta in c.metadata]) })\