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>
save(Archive & a,const Entry & e,const std::uint32_t)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>
load(Archive & a,Entry & e,const std::uint32_t version)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
getEntrySerializePath(uint32_t id,const fs::path & dir)125 fs::path getEntrySerializePath(uint32_t id, const fs::path& dir)
126 {
127 return dir / std::to_string(id);
128 }
129
serialize(const Entry & e,const fs::path & dir)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
deserialize(const fs::path & path,Entry & e)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