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