summaryrefslogtreecommitdiffstats
path: root/log_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'log_manager.cpp')
-rw-r--r--log_manager.cpp133
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
OpenPOWER on IntegriCloud