1 #include "config.h" 2 3 #include "elog_serialize.hpp" 4 5 #include <cereal/archives/binary.hpp> 6 #include <cereal/types/string.hpp> 7 #include <cereal/types/tuple.hpp> 8 #include <cereal/types/vector.hpp> 9 #include <fstream> 10 #include <phosphor-logging/log.hpp> 11 12 // Register class version 13 // From cereal documentation; 14 // "This macro should be placed at global scope" 15 CEREAL_CLASS_VERSION(phosphor::logging::Entry, CLASS_VERSION) 16 17 namespace phosphor 18 { 19 namespace logging 20 { 21 22 /** @brief Function required by Cereal to perform serialization. 23 * @tparam Archive - Cereal archive type (binary in our case). 24 * @param[in] a - reference to Cereal archive. 25 * @param[in] e - const reference to error entry. 26 * @param[in] version - Class version that enables handling 27 * a serialized data across code levels 28 */ 29 template <class Archive> 30 void save(Archive& a, const Entry& e, const std::uint32_t /*version*/) 31 { 32 a(e.id(), e.severity(), e.timestamp(), e.message(), e.additionalData(), 33 e.associations(), e.resolved(), e.version(), e.updateTimestamp(), 34 e.eventId(), e.resolution()); 35 } 36 37 /** @brief Function required by Cereal to perform deserialization. 38 * @tparam Archive - Cereal archive type (binary in our case). 39 * @param[in] a - reference to Cereal archive. 40 * @param[in] e - reference to error entry. 41 * @param[in] version - Class version that enables handling 42 * a serialized data across code levels 43 */ 44 template <class Archive> 45 void load(Archive& a, Entry& e, const std::uint32_t version) 46 { 47 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 48 49 uint32_t id{}; 50 Entry::Level severity{}; 51 uint64_t timestamp{}; 52 std::string message{}; 53 std::vector<std::string> additionalData{}; 54 bool resolved{}; 55 AssociationList associations{}; 56 std::string fwVersion{}; 57 uint64_t updateTimestamp{}; 58 std::string eventId{}; 59 std::string resolution{}; 60 61 if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_FWLEVEL)) 62 { 63 a(id, severity, timestamp, message, additionalData, associations, 64 resolved); 65 updateTimestamp = timestamp; 66 } 67 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_UPDATE_TS)) 68 { 69 a(id, severity, timestamp, message, additionalData, associations, 70 resolved, fwVersion); 71 updateTimestamp = timestamp; 72 } 73 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_EVENTID)) 74 { 75 a(id, severity, timestamp, message, additionalData, associations, 76 resolved, fwVersion, updateTimestamp); 77 } 78 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_RESOLUTION)) 79 { 80 a(id, severity, timestamp, message, additionalData, associations, 81 resolved, fwVersion, updateTimestamp, eventId); 82 } 83 else 84 { 85 a(id, severity, timestamp, message, additionalData, associations, 86 resolved, fwVersion, updateTimestamp, eventId, resolution); 87 } 88 89 e.id(id, true); 90 e.severity(severity, true); 91 e.timestamp(timestamp, true); 92 e.message(message, true); 93 e.additionalData(additionalData, true); 94 e.sdbusplus::xyz::openbmc_project::Logging::server::Entry::resolved( 95 resolved, true); 96 e.associations(associations, true); 97 e.version(fwVersion, true); 98 e.purpose(sdbusplus::xyz::openbmc_project::Software::server::Version:: 99 VersionPurpose::BMC, 100 true); 101 e.updateTimestamp(updateTimestamp, true); 102 e.eventId(eventId, true); 103 e.resolution(resolution, true); 104 } 105 106 fs::path getEntrySerializePath(uint32_t id, const fs::path& dir) 107 { 108 return dir / std::to_string(id); 109 } 110 111 fs::path serialize(const Entry& e, const fs::path& dir) 112 { 113 auto path = getEntrySerializePath(e.id(), dir); 114 std::ofstream os(path.c_str(), std::ios::binary); 115 cereal::BinaryOutputArchive oarchive(os); 116 oarchive(e); 117 return path; 118 } 119 120 bool deserialize(const fs::path& path, Entry& e) 121 { 122 try 123 { 124 if (fs::exists(path)) 125 { 126 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); 127 cereal::BinaryInputArchive iarchive(is); 128 iarchive(e); 129 return true; 130 } 131 return false; 132 } 133 catch (const cereal::Exception& e) 134 { 135 log<level::ERR>(e.what()); 136 fs::remove(path); 137 return false; 138 } 139 catch (const std::length_error& e) 140 { 141 // Running into: USCiLab/cereal#192 142 // This may be indicating some other issue in the 143 // way vector may have been used inside the logging. 144 // possibly associations ??. But handling it here for 145 // now since we are anyway tossing the log 146 // TODO: openbmc/phosphor-logging#8 147 log<level::ERR>(e.what()); 148 fs::remove(path); 149 return false; 150 } 151 } 152 153 } // namespace logging 154 } // namespace phosphor 155