PEL: Create class to read from the journal

Create a Journal class that can extract messages out of the journal and
return them as a vector of strings that look like:

"Dec 14 15:58:17 systemd[1]: systemd-tmpfiles-clean.service: Deactivated
successfully."

It can either grab the previous N entries, or the previous N entries
that match a specific SYSLOG_IDENTIFIER value.

The class follows the same strategy as the DataInterface class where a
base class pointer is passed into the PEL Manager class so that during
unit test it can be mocked.

Future commits will capture the journal into PEL UserData sections.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I9f4bb304c4b213165049fa00de2e62f962ae67f1
diff --git a/extensions/openpower-pels/journal.hpp b/extensions/openpower-pels/journal.hpp
new file mode 100644
index 0000000..1261e32
--- /dev/null
+++ b/extensions/openpower-pels/journal.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <systemd/sd-journal.h>
+
+#include <string>
+#include <vector>
+
+namespace openpower::pels
+{
+
+/**
+ * @class JournalBase
+ * Abstract class to read messages from the journal.
+ */
+class JournalBase
+{
+  public:
+    JournalBase() = default;
+    virtual ~JournalBase() = default;
+    JournalBase(const JournalBase&) = default;
+    JournalBase& operator=(const JournalBase&) = default;
+    JournalBase(JournalBase&&) = default;
+    JournalBase& operator=(JournalBase&&) = default;
+
+    /**
+     * @brief Get messages from the journal
+     *
+     * @param syslogID - The SYSLOG_IDENTIFIER field value
+     * @param maxMessages - Max number of messages to get
+     *
+     * @return The messages
+     */
+    virtual std::vector<std::string> getMessages(const std::string& syslogID,
+                                                 size_t maxMessages) const = 0;
+};
+
+/**
+ * @class Journal
+ *
+ * Reads from the journal.
+ */
+class Journal : public JournalBase
+{
+  public:
+    Journal() = default;
+    ~Journal() = default;
+    Journal(const Journal&) = default;
+    Journal& operator=(const Journal&) = default;
+    Journal(Journal&&) = default;
+    Journal& operator=(Journal&&) = default;
+
+    /**
+     * @brief Get messages from the journal
+     *
+     * @param syslogID - The SYSLOG_IDENTIFIER field value
+     * @param maxMessages - Max number of messages to get
+     *
+     * @return The messages
+     */
+    std::vector<std::string> getMessages(const std::string& syslogID,
+                                         size_t maxMessages) const override;
+
+  private:
+    /**
+     * @brief Gets a field from the current journal entry
+     *
+     * @param journal - pointer to current journal entry
+     * @param field - The field name whose value to get
+     *
+     * @return std::string - The field value
+     */
+    std::string getFieldValue(sd_journal* journal,
+                              const std::string& field) const;
+
+    /**
+     * @brief Gets a readable timestamp from the journal entry
+     *
+     * @param journal - pointer to current journal entry
+     *
+     * @return std::string - A timestamp string
+     */
+    std::string getTimeStamp(sd_journal* journal) const;
+};
+} // namespace openpower::pels