xref: /openbmc/phosphor-logging/elog_serialize.cpp (revision ea6d9c4586d4b9435955124daf5f3afcf4a056c1)
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