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), _fanName(fan), _sensorName(sensor),
101         _severity(
102             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
103                 severity))
104     {}
105 
106     /**
107      * @brief Constructor
108      *
109      * This version doesn't take a fan or sensor name.
110      *
111      * @param[in] error - The error name, like
112      *                    xyz.openbmc_project.Fan.Error.Fault
113      * @param[in] severity - The severity of the error
114      */
FanError(const std::string & error,sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity)115     FanError(const std::string& error,
116              sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level
117                  severity) :
118         _errorName(error),
119         _severity(
120             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
121                 severity))
122     {}
123 
124     /**
125      * @brief Commits the error by calling the D-Bus method to create
126      *        the event log.
127      *
128      * The FFDC is passed in here so that if an error is committed
129      * more than once it can have up to date FFDC.
130      *
131      * @param[in] jsonFFDC - Free form JSON data that should be sent in as
132      *                       FFDC.
133      * @param[in] isPowerOffError - If this is committed at the time of the
134      *                              power off.
135      */
136     void commit(const nlohmann::json& jsonFFDC, bool isPowerOffError = false);
137 
138   private:
139     /**
140      * @brief returns a JSON structure containing the previous N journal
141      * entries.
142      *
143      * @param[in] numLines - Number of lines of journal to retrieve
144      */
145     nlohmann::json getJournalEntries(int numLines) const;
146 
147     /**
148      * Gets the realtime (wallclock) timestamp for the current journal entry.
149      *
150      * @param journal current journal entry
151      * @return timestamp as a date/time string
152      */
153     std::string getTimeStamp(sd_journal* journal) const;
154 
155     /**
156      * Gets the value of the specified field for the current journal entry.
157      *
158      * Returns an empty string if the current journal entry does not have the
159      * specified field.
160      *
161      * @param journal current journal entry
162      * @param field journal field name
163      * @return field value
164      */
165     std::string getFieldValue(sd_journal* journal,
166                               const std::string& field) const;
167 
168     /**
169      * @brief Returns an FFDCFile holding the Logger contents
170      *
171      * @return std::unique_ptr<FFDCFile> - The file object
172      */
173     std::unique_ptr<FFDCFile> makeLogFFDCFile();
174 
175     /**
176      * @brief Returns an FFDCFile holding the contents of the JSON FFDC
177      *
178      * @param[in] ffdcData - The JSON data to write to a file
179      *
180      * @return std::unique_ptr<FFDCFile> - The file object
181      */
182     std::unique_ptr<FFDCFile> makeJsonFFDCFile(const nlohmann::json& ffdcData);
183 
184     /**
185      * @brief Create and returns the AdditionalData property to use for the
186      *        event log.
187      *
188      * @param[in] isPowerOffError - If this is committed at the time of the
189      *                              power off.
190      * @return map<string, string> - The AdditionalData contents
191      */
192     std::map<std::string, std::string> getAdditionalData(bool isPowerOffError);
193 
194     /**
195      * @brief The error name (The event log's 'Message' property)
196      */
197     const std::string _errorName;
198 
199     /**
200      * @brief The inventory name of the failing fan
201      */
202     const std::string _fanName;
203 
204     /**
205      * @brief The inventory name of the failing sensor, if there is one.
206      */
207     const std::string _sensorName;
208 
209     /**
210      * @brief The severity of the event log.  This is the string
211      *        representation of the Entry::Level property.
212      */
213     const std::string _severity;
214 };
215 
216 } // namespace phosphor::fan::monitor
217