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