1 #pragma once
2 
3 #include "utility.hpp"
4 
5 #include <nlohmann/json.hpp>
6 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
7 
8 #include <filesystem>
9 #include <string>
10 #include <tuple>
11 
12 namespace phosphor::fan::monitor
13 {
14 
15 /**
16  * @class FFDCFile
17  *
18  * This class holds a file that is used for event log FFDC
19  * which needs a file descriptor as input.  The file is
20  * deleted upon destruction.
21  */
22 class FFDCFile
23 {
24   public:
25     FFDCFile() = delete;
26     FFDCFile(const FFDCFile&) = delete;
27     FFDCFile& operator=(const FFDCFile&) = delete;
28     FFDCFile(FFDCFile&&) = delete;
29     FFDCFile& operator=(FFDCFile&&) = delete;
30 
31     /**
32      * @brief Constructor
33      *
34      * Opens the file and saves the descriptor
35      *
36      * @param[in] name - The filename
37      */
38     explicit FFDCFile(const std::filesystem::path& name);
39 
40     /**
41      * @brief Destructor - Deletes the file
42      */
~FFDCFile()43     ~FFDCFile()
44     {
45         std::filesystem::remove(_name);
46     }
47 
48     /**
49      * @brief Returns the file descriptor
50      *
51      * @return int - The descriptor
52      */
fd()53     int fd()
54     {
55         return _fd();
56     }
57 
58   private:
59     /**
60      * @brief The file descriptor holder
61      */
62     util::FileDescriptor _fd;
63 
64     /**
65      * @brief The filename
66      */
67     const std::filesystem::path _name;
68 };
69 
70 /**
71  * @class FanError
72  *
73  * This class represents a fan error.  It has a commit() interface
74  * that will create the event log with certain FFDC.
75  */
76 class FanError
77 {
78   public:
79     FanError() = delete;
80     ~FanError() = default;
81     FanError(const FanError&) = delete;
82     FanError& operator=(const FanError&) = delete;
83     FanError(FanError&&) = delete;
84     FanError& operator=(FanError&&) = delete;
85 
86     /**
87      * @brief Constructor
88      *
89      * @param[in] error - The error name, like
90      *                    xyz.openbmc_project.Fan.Error.Fault
91      * @param[in] fan - The failing fan's inventory path
92      * @param[in] sensor - The failing sensor's inventory path.  Can be empty
93      *                     if the error is for the FRU and not the sensor.
94      * @param[in] severity - The severity of the error
95      */
FanError(const std::string & error,const std::string & fan,const std::string & sensor,sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity)96     FanError(const std::string& error, const std::string& fan,
97              const std::string& sensor,
98              sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level
99                  severity) :
100         _errorName(error),
101         _fanName(fan), _sensorName(sensor),
102         _severity(
103             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
104                 severity))
105     {}
106 
107     /**
108      * @brief Constructor
109      *
110      * This version doesn't take a fan or sensor name.
111      *
112      * @param[in] error - The error name, like
113      *                    xyz.openbmc_project.Fan.Error.Fault
114      * @param[in] severity - The severity of the error
115      */
FanError(const std::string & error,sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity)116     FanError(const std::string& error,
117              sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level
118                  severity) :
119         _errorName(error),
120         _severity(
121             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
122                 severity))
123     {}
124 
125     /**
126      * @brief Commits the error by calling the D-Bus method to create
127      *        the event log.
128      *
129      * The FFDC is passed in here so that if an error is committed
130      * more than once it can have up to date FFDC.
131      *
132      * @param[in] jsonFFDC - Free form JSON data that should be sent in as
133      *                       FFDC.
134      * @param[in] isPowerOffError - If this is committed at the time of the
135      *                              power off.
136      */
137     void commit(const nlohmann::json& jsonFFDC, bool isPowerOffError = false);
138 
139   private:
140     /**
141      * @brief returns a JSON structure containing the previous N journal
142      * entries.
143      *
144      * @param[in] numLines - Number of lines of journal to retrieve
145      */
146     nlohmann::json getJournalEntries(int numLines) const;
147 
148     /**
149      * Gets the realtime (wallclock) timestamp for the current journal entry.
150      *
151      * @param journal current journal entry
152      * @return timestamp as a date/time string
153      */
154     std::string getTimeStamp(sd_journal* journal) const;
155 
156     /**
157      * Gets the value of the specified field for the current journal entry.
158      *
159      * Returns an empty string if the current journal entry does not have the
160      * specified field.
161      *
162      * @param journal current journal entry
163      * @param field journal field name
164      * @return field value
165      */
166     std::string getFieldValue(sd_journal* journal,
167                               const std::string& field) const;
168 
169     /**
170      * @brief Returns an FFDCFile holding the Logger contents
171      *
172      * @return std::unique_ptr<FFDCFile> - The file object
173      */
174     std::unique_ptr<FFDCFile> makeLogFFDCFile();
175 
176     /**
177      * @brief Returns an FFDCFile holding the contents of the JSON FFDC
178      *
179      * @param[in] ffdcData - The JSON data to write to a file
180      *
181      * @return std::unique_ptr<FFDCFile> - The file object
182      */
183     std::unique_ptr<FFDCFile> makeJsonFFDCFile(const nlohmann::json& ffdcData);
184 
185     /**
186      * @brief Create and returns the AdditionalData property to use for the
187      *        event log.
188      *
189      * @param[in] isPowerOffError - If this is committed at the time of the
190      *                              power off.
191      * @return map<string, string> - The AdditionalData contents
192      */
193     std::map<std::string, std::string> getAdditionalData(bool isPowerOffError);
194 
195     /**
196      * @brief The error name (The event log's 'Message' property)
197      */
198     const std::string _errorName;
199 
200     /**
201      * @brief The inventory name of the failing fan
202      */
203     const std::string _fanName;
204 
205     /**
206      * @brief The inventory name of the failing sensor, if there is one.
207      */
208     const std::string _sensorName;
209 
210     /**
211      * @brief The severity of the event log.  This is the string
212      *        representation of the Entry::Level property.
213      */
214     const std::string _severity;
215 };
216 
217 } // namespace phosphor::fan::monitor
218