diff options
Diffstat (limited to 'log_manager.cpp')
-rw-r--r-- | log_manager.cpp | 133 |
1 files changed, 115 insertions, 18 deletions
diff --git a/log_manager.cpp b/log_manager.cpp index 3dc14d7..569413a 100644 --- a/log_manager.cpp +++ b/log_manager.cpp @@ -5,6 +5,7 @@ #include "elog_entry.hpp" #include "elog_meta.hpp" #include "elog_serialize.hpp" +#include "extensions.hpp" #include <poll.h> #include <sys/inotify.h> @@ -12,6 +13,7 @@ #include <systemd/sd-journal.h> #include <unistd.h> +#include <cassert> #include <chrono> #include <cstdio> #include <cstring> @@ -77,20 +79,6 @@ void Manager::commitWithLvl(uint64_t transactionId, std::string errMsg, void Manager::_commit(uint64_t transactionId, std::string&& errMsg, Entry::Level errLvl) { - if (errLvl < Entry::sevLowerLimit) - { - if (realErrors.size() >= ERROR_CAP) - { - erase(realErrors.front()); - } - } - else - { - if (infoErrors.size() >= ERROR_INFO_CAP) - { - erase(infoErrors.front()); - } - } constexpr const auto transactionIdVar = "TRANSACTION_ID"; // Length of 'TRANSACTION_ID' string. constexpr const auto transactionIdVarSize = std::strlen(transactionIdVar); @@ -193,7 +181,30 @@ void Manager::_commit(uint64_t transactionId, std::string&& errMsg, sd_journal_close(j); - // Create error Entry dbus object + createEntry(errMsg, errLvl, additionalData); +} + +void Manager::createEntry(std::string errMsg, Entry::Level errLvl, + std::vector<std::string> additionalData) +{ + if (!Extensions::disableDefaultLogCaps()) + { + if (errLvl < Entry::sevLowerLimit) + { + if (realErrors.size() >= ERROR_CAP) + { + erase(realErrors.front()); + } + } + else + { + if (infoErrors.size() >= ERROR_INFO_CAP) + { + erase(infoErrors.front()); + } + } + } + entryId++; if (errLvl >= Entry::sevLowerLimit) { @@ -217,9 +228,39 @@ void Manager::_commit(uint64_t transactionId, std::string&& errMsg, std::move(additionalData), std::move(objects), fwVersion, *this); serialize(*e); + + doExtensionLogCreate(*e); + entries.insert(std::make_pair(entryId, std::move(e))); } +void Manager::doExtensionLogCreate(const Entry& entry) +{ + // Make the association <endpointpath>/<endpointtype> paths + std::vector<std::string> assocs; + for (const auto& [forwardType, reverseType, endpoint] : + entry.associations()) + { + std::string e{endpoint}; + e += '/' + reverseType; + assocs.push_back(e); + } + + for (auto& create : Extensions::getCreateFunctions()) + { + try + { + create(entry.message(), entry.id(), entry.timestamp(), + entry.severity(), entry.additionalData(), assocs); + } + catch (std::exception& e) + { + log<level::ERR>("An extension's create function threw an exception", + phosphor::logging::entry("ERROR=%s", e.what())); + } + } +} + void Manager::processMetadata(const std::string& errorName, const std::vector<std::string>& additionalData, AssociationList& objects) const @@ -246,6 +287,27 @@ void Manager::erase(uint32_t entryId) auto entryFound = entries.find(entryId); if (entries.end() != entryFound) { + for (auto& func : Extensions::getDeleteProhibitedFunctions()) + { + try + { + bool prohibited = false; + func(entryId, prohibited); + if (prohibited) + { + // Future work remains to throw an error here. + return; + } + } + catch (std::exception& e) + { + log<level::ERR>( + "An extension's deleteProhibited function threw " + "an exception", + entry("ERROR=%s", e.what())); + } + } + // Delete the persistent representation of this error. fs::path errorPath(ERRLOG_PERSIST_PATH); errorPath /= std::to_string(entryId); @@ -267,6 +329,20 @@ void Manager::erase(uint32_t entryId) removeId(realErrors, entryId); } entries.erase(entryFound); + + for (auto& remove : Extensions::getDeleteFunctions()) + { + try + { + remove(entryId); + } + catch (std::exception& e) + { + log<level::ERR>("An extension's delete function threw an " + "exception", + entry("ERROR=%s", e.what())); + } + } } else { @@ -341,7 +417,18 @@ void Manager::journalSync() duration_cast<microseconds>(steady_clock::now().time_since_epoch()) .count(); - constexpr auto maxRetry = 2; + // Each time an error log is committed, a request to sync the journal + // must occur and block that error log commit until it completes. A 5sec + // block is done to allow sufficient time for the journal to be synced. + // + // Number of loop iterations = 3 for the following reasons: + // Iteration #1: Requests a journal sync by killing the journald service. + // Iteration #2: Setup an inotify watch to monitor the synced file that + // journald updates with the timestamp the last time the + // journal was flushed. + // Iteration #3: Poll to wait until inotify reports an event which blocks + // the error log from being commited until the sync completes. + constexpr auto maxRetry = 3; for (int i = 0; i < maxRetry; i++) { // Read timestamp from synced file @@ -367,7 +454,7 @@ void Manager::journalSync() auto timestamp = std::stoll(timestampStr); if (timestamp >= start) { - return; + break; } } @@ -386,7 +473,7 @@ void Manager::journalSync() if (method.is_method_error()) { log<level::ERR>("Failed to kill journal service"); - return; + break; } continue; } @@ -486,6 +573,16 @@ std::string Manager::readFWVersion() return version; } +void Manager::create(const std::string& message, Entry::Level severity, + const std::map<std::string, std::string>& additionalData) +{ + // Convert the map into a vector of "key=value" strings + std::vector<std::string> ad; + metadata::associations::combine(additionalData, ad); + + createEntry(message, severity, ad); +} + } // namespace internal } // namespace logging } // namespace phosphor |