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