| #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] creator - The function to use to create the event log |
| */ |
| explicit EventLogger(LogFunction creator) : |
| _event(sdeventplus::Event::get_default()), _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 (const 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 |