summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels/event_logger.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/openpower-pels/event_logger.hpp')
-rw-r--r--extensions/openpower-pels/event_logger.hpp187
1 files changed, 187 insertions, 0 deletions
diff --git a/extensions/openpower-pels/event_logger.hpp b/extensions/openpower-pels/event_logger.hpp
new file mode 100644
index 0000000..b4df0d4
--- /dev/null
+++ b/extensions/openpower-pels/event_logger.hpp
@@ -0,0 +1,187 @@
+#pragma once
+
+#include "additional_data.hpp"
+#include "elog_entry.hpp"
+
+#include <phosphor-logging/log.hpp>
+#include <queue>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/source/event.hpp>
+#include <tuple>
+
+namespace openpower::pels
+{
+
+/**
+ * @class EventLogger
+ *
+ * This class handles creating OpenBMC event logs (and thus PELs) from
+ * within the PEL extension code.
+ *
+ * The function to actually create the event log is passed in via the
+ * constructor so that different functions can be used when testing.
+ *
+ * To create the event log, call log() with the appropriate arguments
+ * and the log will be created as soon as the flow gets back to the event
+ * loop. If the queue isn't empty after a log is created, the next
+ * one will be scheduled to be created from the event loop again.
+ *
+ * This class does not allow new events to be added while inside the
+ * creation function, because if the code added an event log every time
+ * it tried to create one, it would do so infinitely.
+ */
+class EventLogger
+{
+ public:
+ using ADMap = std::map<std::string, std::string>;
+ using LogFunction = std::function<void(
+ const std::string&, phosphor::logging::Entry::Level, const ADMap&)>;
+
+ static constexpr size_t msgPos = 0;
+ static constexpr size_t levelPos = 1;
+ static constexpr size_t adPos = 2;
+ using EventEntry = std::tuple<std::string, phosphor::logging::Entry::Level,
+ AdditionalData>;
+
+ EventLogger() = delete;
+ ~EventLogger() = default;
+ EventLogger(const EventLogger&) = delete;
+ EventLogger& operator=(const EventLogger&) = delete;
+ EventLogger(EventLogger&&) = delete;
+ EventLogger& operator=(EventLogger&&) = delete;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] event - The sd_event object
+ * @param[in] creator - The function to use to create the event log
+ */
+ EventLogger(sd_event* event, LogFunction creator) :
+ _event(event), _creator(creator)
+ {
+ }
+
+ /**
+ * @brief Adds an event to the queue so that it will be created
+ * as soon as the code makes it back to the event loop.
+ *
+ * Won't add it to the queue if already inside the create()
+ * callback.
+ *
+ * @param[in] message - The message property of the event log
+ * @param[in] severity - The severity level of the event log
+ * @param[in] ad - The additional data property of the event log
+ */
+ void log(const std::string& message,
+ phosphor::logging::Entry::Level severity, const AdditionalData& ad)
+ {
+ if (!_inEventCreation)
+ {
+ _eventsToCreate.emplace(message, severity, ad);
+
+ if (!_eventSource)
+ {
+ scheduleCreate();
+ }
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Already in event create callback, skipping new create",
+ phosphor::logging::entry("ERROR_NAME=%s", message.c_str()));
+ }
+ }
+
+ /**
+ * @brief Returns the event log queue size.
+ *
+ * @return size_t - The queue size
+ */
+ size_t queueSize() const
+ {
+ return _eventsToCreate.size();
+ }
+
+ /**
+ * @brief Schedules the create() function to run using the
+ * 'defer' sd_event source.
+ */
+ void scheduleCreate()
+ {
+ _eventSource = std::make_unique<sdeventplus::source::Defer>(
+ _event, std::bind(std::mem_fn(&EventLogger::create), this,
+ std::placeholders::_1));
+ }
+
+ private:
+ /**
+ * @brief Creates an event log and schedules the next one if
+ * there is one.
+ *
+ * This gets called from the event loop by the sd_event code.
+ *
+ * @param[in] source - The event source object used
+ */
+ void create(sdeventplus::source::EventBase& source)
+ {
+ _eventSource.reset();
+
+ if (_eventsToCreate.empty())
+ {
+ return;
+ }
+
+ auto event = _eventsToCreate.front();
+ _eventsToCreate.pop();
+
+ _inEventCreation = true;
+
+ try
+ {
+ _creator(std::get<msgPos>(event), std::get<levelPos>(event),
+ std::get<adPos>(event).getData());
+ }
+ catch (std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "EventLogger's create function threw an exception",
+ phosphor::logging::entry("ERROR=%s", e.what()));
+ }
+
+ _inEventCreation = false;
+
+ if (!_eventsToCreate.empty())
+ {
+ scheduleCreate();
+ }
+ }
+
+ /**
+ * @brief The sd_event object.
+ */
+ sdeventplus::Event _event;
+
+ /**
+ * @brief The user supplied function to create the event log.
+ */
+ LogFunction _creator;
+
+ /**
+ * @brief Keeps track of if an event is currently being created.
+ *
+ * Guards against creating new events while creating events.
+ */
+ bool _inEventCreation = false;
+
+ /**
+ * @brief The event source object used for scheduling.
+ */
+ std::unique_ptr<sdeventplus::source::Defer> _eventSource;
+
+ /**
+ * @brief The queue of event logs to create.
+ */
+ std::queue<EventEntry> _eventsToCreate;
+};
+
+} // namespace openpower::pels
OpenPOWER on IntegriCloud