PEL: Capture the journal in UserData sections

If a PEL message registry entry has a 'JournalCapture' section, capture
the listed portions of the journal in UserData sections for that error.

If the JSON looks like:

"JournalCapture": {
    "NumLines": 30
}

Then the code will capture the previous 30 lines from the journal into a
single UserData section.

If the JSON looks like:

"JournalCapture":
{
    "Sections": [
        {
            "SyslogID": "phosphor-bmc-state-manager",
            "NumLines": 20
        },
        {
            "SyslogID": "phosphor-log-manager",
            "NumLines": 15
        }
    ]
}

Then the code will create two UserData sections, the first with the most
recent 20 lines from phosphor-bmc-state-manager, and the second with 15
lines from phosphor-log-manager.

If a section would cause the PEL to exceed its maximum size of 16KB, it
will be dropped.  While the UserData class does have a shrink() method,
it prunes data from the end, which would cause the most recent journal
entries to be removed, which could be misleading.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I2ecbd8002b0e7087eb166a1219c6ab9da14a122a
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 460d588..d6f76e1 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -2,6 +2,7 @@
 
 #include "additional_data.hpp"
 #include "data_interface.hpp"
+#include "journal.hpp"
 #include "private_header.hpp"
 #include "registry.hpp"
 #include "src.hpp"
@@ -105,11 +106,12 @@
      * @param[in] additionalData - The AdditionalData contents
      * @param[in] ffdcFiles - FFCD files that go into UserData sections
      * @param[in] dataIface - The data interface object
+     * @param[in] journal - The journal object
      */
     PEL(const openpower::pels::message::Entry& entry, uint32_t obmcLogID,
         uint64_t timestamp, phosphor::logging::Entry::Level severity,
         const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
-        const DataInterfaceBase& dataIface);
+        const DataInterfaceBase& dataIface, const JournalBase& journal);
 
     /**
      * @brief Convenience function to return the log ID field from the
@@ -381,6 +383,16 @@
     void updateTerminateBitInSRCSection();
 
     /**
+     * @brief Adds journal data to the PEL as UserData sections
+     *        if specified to in the message registry.
+     *
+     * @param regEntry - The registry entry
+     * @param journal - The journal object
+     */
+    void addJournalSections(const message::Entry& regEntry,
+                            const JournalBase& journal);
+
+    /**
      * @brief The PEL Private Header section
      */
     std::unique_ptr<PrivateHeader> _ph;
@@ -457,6 +469,19 @@
  */
 std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
                                                   const PelFFDCfile& file);
+
+/**
+ * @brief Flattens a vector of strings into a vector of bytes suitable
+ *        for storing in a PEL section.
+ *
+ * Adds a newline character after each string.
+ *
+ * @param lines - The vector of strings to convert
+ *
+ * @return std::vector<uint8_t> - The flattened data
+ */
+std::vector<uint8_t> flattenLines(const std::vector<std::string>& lines);
+
 } // namespace util
 
 } // namespace pels