diff options
author | Deepak Kodihalli <dkodihal@in.ibm.com> | 2017-06-12 04:33:29 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-06-26 02:33:34 +0000 |
commit | 72654f10e45056ab55b77d835e2bfd01e8d98480 (patch) | |
tree | a81c82f786690244abf0a8be2185e6c775cabac5 | |
parent | 979632aeb629b4cb62aed276f7422c34cd7983bc (diff) | |
download | phosphor-logging-72654f10e45056ab55b77d835e2bfd01e8d98480.tar.gz phosphor-logging-72654f10e45056ab55b77d835e2bfd01e8d98480.zip |
Persist error d-bus objects
Use Cereal to implement serialization and de-serialization of
properties of error d-bus objects.
Serialize and persist error d-bus objects as they are put on the bus.
De-serialize and restore them (if persistent ones exist) when
phosphor-log-manager starts up.
Change-Id: I1f5df1abbe74bfdb86e3e82a78ff7115e90e2112
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | elog_entry.hpp | 20 | ||||
-rw-r--r-- | elog_serialize.cpp | 35 | ||||
-rw-r--r-- | elog_serialize.hpp | 78 | ||||
-rw-r--r-- | log_manager.cpp | 54 | ||||
-rw-r--r-- | log_manager.hpp | 5 | ||||
-rw-r--r-- | log_manager_main.cpp | 7 |
8 files changed, 198 insertions, 13 deletions
diff --git a/Makefile.am b/Makefile.am index 6ca02d3..29f18d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,8 @@ phosphor_log_manager_SOURCES = \ elog_entry.cpp \ org.openbmc.Associations.cpp \ elog-process-metadata.cpp \ - elog_meta.cpp + elog_meta.cpp \ + elog_serialize.cpp # Be sure to build needed files before compiling BUILT_SOURCES = \ @@ -64,7 +65,8 @@ callout_test_CXXFLAGS = $(SDBUSPLUS_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) phosphor_log_manager_LDFLAGS = \ $(SYSTEMD_LIBS) \ $(SDBUSPLUS_LIBS) \ - $(PHOSPHOR_DBUS_INTERFACES_LIBS) + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ + -lstdc++fs phosphor_log_manager_CXXFLAGS = \ $(SYSTEMD_CFLAGS) \ $(SDBUSPLUS_CFLAGS) \ diff --git a/configure.ac b/configure.ac index 7055888..977bcb0 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,12 @@ AC_ARG_VAR(CALLOUTS_YAML, [YAML filepath containing generated callouts.]) AS_IF([test "x$CALLOUTS_YAML" == "x"], \ [CALLOUTS_YAML="callouts-example.yaml"]) +AC_ARG_VAR(ERRLOG_PERSIST_PATH, [Path of directory housing persisted errors.]) +AS_IF([test "x$ERRLOG_PERSIST_PATH" == "x"], \ + [ERRLOG_PERSIST_PATH="/var/lib/phosphor-logging/errors"]) +AC_DEFINE_UNQUOTED([ERRLOG_PERSIST_PATH], ["$ERRLOG_PERSIST_PATH"], \ + [Path of directory housing persisted errors]) + # Compile error metadata handlers if we're asked to do so. AC_ARG_ENABLE([metadata-processing], AS_HELP_STRING([--enable-metadata-processing], [Compile metadata handlers]), diff --git a/elog_entry.hpp b/elog_entry.hpp index 06f6bc2..ffff8af 100644 --- a/elog_entry.hpp +++ b/elog_entry.hpp @@ -75,6 +75,24 @@ class Entry : public EntryIfaces this->emit_object_added(); }; + /** @brief Constructor that puts an "empty" error object on the bus, + * with only the id property populated. Rest of the properties + * to be set by the caller. Caller should emit the added signal. + * @param[in] bus - Bus to attach to. + * @param[in] path - Path to attach at. + * @param[in] id - The error entry id. + * @param[in] parent - The error's parent. + */ + Entry(sdbusplus::bus::bus& bus, + const std::string& path, + uint32_t entryId, + Manager& parent) : + EntryIfaces(bus, path.c_str(), true), + parent(parent) + { + id(entryId); + }; + /** @brief Set resolution status of the error. * @param[in] value - boolean indicating resolution * status (true = resolved) @@ -89,6 +107,8 @@ class Entry : public EntryIfaces return sdbusplus::xyz::openbmc_project:: Logging::server::Entry::resolved(value); } + using sdbusplus::xyz::openbmc_project:: + Logging::server::Entry::resolved; /** @brief Delete this d-bus object. */ diff --git a/elog_serialize.cpp b/elog_serialize.cpp new file mode 100644 index 0000000..0468e11 --- /dev/null +++ b/elog_serialize.cpp @@ -0,0 +1,35 @@ +#include <cereal/types/string.hpp> +#include <cereal/types/vector.hpp> +#include <cereal/types/tuple.hpp> +#include <cereal/archives/binary.hpp> +#include <fstream> +#include "elog_serialize.hpp" + +namespace phosphor +{ +namespace logging +{ + +fs::path serialize(const Entry& e, const fs::path& dir) +{ + auto path = dir / std::to_string(e.id()); + std::ofstream os(path.c_str(), std::ios::binary); + cereal::BinaryOutputArchive oarchive(os); + oarchive(e); + return path; +} + +bool deserialize(const fs::path& path, Entry& e) +{ + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); + cereal::BinaryInputArchive iarchive(is); + iarchive(e); + return true; + } + return false; +} + +} // namespace logging +} // namespace phosphor diff --git a/elog_serialize.hpp b/elog_serialize.hpp new file mode 100644 index 0000000..d1bcbfb --- /dev/null +++ b/elog_serialize.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include <string> +#include <vector> +#include <experimental/filesystem> +#include "elog_entry.hpp" +#include "config.h" + +namespace phosphor +{ +namespace logging +{ + +namespace fs = std::experimental::filesystem; + +/** @brief Function required by Cereal to perform serialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] a - reference to Cereal archive. + * @param[in] e - const reference to error entry. + */ +template<class Archive> +void save(Archive& a, const Entry& e) +{ + a(e.id(), e.severity(), e.timestamp(), + e.message(), e.additionalData(), e.associations(), e.resolved()); +} + +/** @brief Function required by Cereal to perform deserialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] a - reference to Cereal archive. + * @param[in] e - reference to error entry. + */ +template<class Archive> +void load(Archive& a, Entry& e) +{ + using namespace + sdbusplus::xyz::openbmc_project::Logging::server; + + uint32_t id{}; + Entry::Level severity{}; + uint64_t timestamp{}; + std::string message{}; + std::vector<std::string> additionalData{}; + bool resolved{}; + AssociationList associations{}; + + a(id, severity, timestamp, message, + additionalData, associations, resolved); + + e.id(id); + e.severity(severity); + e.timestamp(timestamp); + e.message(message); + e.additionalData(additionalData); + e.sdbusplus::xyz::openbmc_project:: + Logging::server::Entry::resolved(resolved); + e.associations(associations); +} + +/** @brief Serialize and persist error d-bus object + * @param[in] a - const reference to error entry. + * @param[in] dir - pathname of directory where the serialized error will + * be placed. + * @return fs::path - pathname of persisted error file + */ +fs::path serialize(const Entry& e, + const fs::path& dir = fs::path(ERRLOG_PERSIST_PATH)); + +/** @brief Deserialze a persisted error into a d-bus object + * @param[in] path - pathname of persisted error file + * @param[in] e - reference to error object which is the target of + * deserialization. + * @return bool - true if the deserialization was successful, false otherwise. + */ +bool deserialize(const fs::path& path, Entry& e); + +} // namespace logging +} // namespace phosphor diff --git a/log_manager.cpp b/log_manager.cpp index 8ab495b..3f61e91 100644 --- a/log_manager.cpp +++ b/log_manager.cpp @@ -14,6 +14,7 @@ #include <phosphor-logging/log.hpp> #include "log_manager.hpp" #include "elog_meta.hpp" +#include "elog_serialize.hpp" using namespace phosphor::logging; extern const std::map<metadata::Metadata, @@ -145,17 +146,18 @@ void Manager::commit(uint64_t transactionId, std::string errMsg) { reqLevel = levelmap->second; } - entries.insert(std::make_pair(entryId, std::make_unique<Entry>( - busLog, - objPath, - entryId, - ms, // Milliseconds since 1970 - static_cast<Entry::Level>(reqLevel), - std::move(errMsg), - std::move(additionalData), - std::move(objects), - *this))); - return; + auto e = std::make_unique<Entry>( + busLog, + objPath, + entryId, + ms, // Milliseconds since 1970 + static_cast<Entry::Level>(reqLevel), + std::move(errMsg), + std::move(additionalData), + std::move(objects), + *this); + serialize(*e); + entries.insert(std::make_pair(entryId, std::move(e))); } void Manager::processMetadata(const std::string& errorName, @@ -188,5 +190,35 @@ void Manager::erase(uint32_t entryId) } } +void Manager::restore() +{ + std::vector<uint32_t> errorIds; + + fs::path dir(ERRLOG_PERSIST_PATH); + if (!fs::exists(dir) || fs::is_empty(dir)) + { + return; + } + + for(auto& file: fs::directory_iterator(dir)) + { + auto id = file.path().filename().c_str(); + auto idNum = std::stol(id); + auto e = std::make_unique<Entry>( + busLog, + std::string(OBJ_ENTRY) + '/' + id, + idNum, + *this); + if (deserialize(file.path(), *e)) + { + e->emit_object_added(); + entries.insert(std::make_pair(idNum, std::move(e))); + errorIds.push_back(idNum); + } + } + + entryId = *(std::max_element(errorIds.begin(), errorIds.end())); +} + } // namespace logging } // namepsace phosphor diff --git a/log_manager.hpp b/log_manager.hpp index 71b6e71..730f63e 100644 --- a/log_manager.hpp +++ b/log_manager.hpp @@ -67,6 +67,11 @@ class Manager : public details::ServerObject<details::ManagerIface> */ void erase(uint32_t entryId); + /** @brief Construct error d-bus objects from their persisted + * representations. + */ + void restore(); + private: /** @brief Call metadata handler(s), if any. Handlers may create * associations. diff --git a/log_manager_main.cpp b/log_manager_main.cpp index a3b26a3..b04c0e3 100644 --- a/log_manager_main.cpp +++ b/log_manager_main.cpp @@ -1,5 +1,6 @@ #include <sdbusplus/bus.hpp> #include <sdbusplus/server/manager.hpp> +#include <experimental/filesystem> #include "config.h" #include "log_manager.hpp" @@ -12,6 +13,12 @@ int main(int argc, char *argv[]) phosphor::logging::Manager manager(bus, OBJ_INTERNAL); + // Create a directory to persist errors. + std::experimental::filesystem::create_directories(ERRLOG_PERSIST_PATH); + + // Recreate error d-bus objects from persisted errors. + manager.restore(); + bus.request_name(BUSNAME_LOGGING); while(true) |