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