1 /**
2  * Copyright © 2021 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "error_logging_utils.hpp"
18 
19 #include "config_file_parser_error.hpp"
20 #include "exception_utils.hpp"
21 #include "i2c_interface.hpp"
22 #include "journal.hpp"
23 #include "pmbus_error.hpp"
24 #include "write_verification_error.hpp"
25 
26 #include <sdbusplus/exception.hpp>
27 
28 #include <vector>
29 
30 namespace phosphor::power::regulators::error_logging_utils
31 {
32 
logError(std::exception_ptr eptr,Entry::Level severity,Services & services)33 void logError(std::exception_ptr eptr, Entry::Level severity,
34               Services& services)
35 {
36     // Specify empty error history so that all error types will be logged
37     ErrorHistory history{};
38     logError(eptr, severity, services, history);
39 }
40 
logError(std::exception_ptr eptr,Entry::Level severity,Services & services,ErrorHistory & history)41 void logError(std::exception_ptr eptr, Entry::Level severity,
42               Services& services, ErrorHistory& history)
43 {
44     // Check for null exception pointer
45     if (!eptr)
46     {
47         return;
48     }
49 
50     // Get exception to log from specified exception and any nested exceptions
51     std::exception_ptr exceptionToLog = internal::getExceptionToLog(eptr);
52 
53     // Log an error based on the exception
54     ErrorLogging& errorLogging = services.getErrorLogging();
55     Journal& journal = services.getJournal();
56     ErrorType errorType{};
57     try
58     {
59         std::rethrow_exception(exceptionToLog);
60     }
61     catch (const ConfigFileParserError& e)
62     {
63         errorType = ErrorType::configFile;
64         if (!history.wasLogged(errorType))
65         {
66             history.setWasLogged(errorType, true);
67             errorLogging.logConfigFileError(severity, journal);
68         }
69     }
70     catch (const PMBusError& e)
71     {
72         errorType = ErrorType::pmbus;
73         if (!history.wasLogged(errorType))
74         {
75             history.setWasLogged(errorType, true);
76             errorLogging.logPMBusError(severity, journal, e.getInventoryPath());
77         }
78     }
79     catch (const WriteVerificationError& e)
80     {
81         errorType = ErrorType::writeVerification;
82         if (!history.wasLogged(errorType))
83         {
84             history.setWasLogged(errorType, true);
85             errorLogging.logWriteVerificationError(severity, journal,
86                                                    e.getInventoryPath());
87         }
88     }
89     catch (const i2c::I2CException& e)
90     {
91         errorType = ErrorType::i2c;
92         if (!history.wasLogged(errorType))
93         {
94             history.setWasLogged(errorType, true);
95             errorLogging.logI2CError(severity, journal, e.bus, e.addr,
96                                      e.errorCode);
97         }
98     }
99     catch (const sdbusplus::exception_t& e)
100     {
101         errorType = ErrorType::dbus;
102         if (!history.wasLogged(errorType))
103         {
104             history.setWasLogged(errorType, true);
105             errorLogging.logDBusError(severity, journal);
106         }
107     }
108     catch (const std::exception& e)
109     {
110         errorType = ErrorType::internal;
111         if (!history.wasLogged(errorType))
112         {
113             history.setWasLogged(errorType, true);
114             errorLogging.logInternalError(severity, journal);
115         }
116     }
117     catch (...)
118     {
119         errorType = ErrorType::internal;
120         if (!history.wasLogged(errorType))
121         {
122             history.setWasLogged(errorType, true);
123             errorLogging.logInternalError(severity, journal);
124         }
125     }
126 }
127 
128 namespace internal
129 {
130 
getExceptionToLog(std::exception_ptr eptr)131 std::exception_ptr getExceptionToLog(std::exception_ptr eptr)
132 {
133     // Default to selecting the outermost exception
134     std::exception_ptr exceptionToLog{eptr};
135 
136     // Get vector containing this exception and any nested exceptions
137     std::vector<std::exception_ptr> exceptions =
138         exception_utils::getExceptions(eptr);
139 
140     // Define temporary constants for exception priorities
141     const int lowPriority{0}, mediumPriority{1}, highPriority{2};
142 
143     // Loop through the exceptions from innermost to outermost.  Find the
144     // exception with the highest priority.  If there is a tie, select the
145     // outermost exception with that priority.
146     int highestPriorityFound{-1};
147     for (std::exception_ptr curptr : exceptions)
148     {
149         int priority{-1};
150         try
151         {
152             std::rethrow_exception(curptr);
153         }
154         catch (const ConfigFileParserError& e)
155         {
156             priority = highPriority;
157         }
158         catch (const PMBusError& e)
159         {
160             priority = highPriority;
161         }
162         catch (const WriteVerificationError& e)
163         {
164             priority = highPriority;
165         }
166         catch (const i2c::I2CException& e)
167         {
168             priority = highPriority;
169         }
170         catch (const sdbusplus::exception_t& e)
171         {
172             priority = mediumPriority;
173         }
174         catch (const std::exception& e)
175         {
176             priority = lowPriority;
177         }
178         catch (...)
179         {
180             priority = lowPriority;
181         }
182 
183         if (priority >= highestPriorityFound)
184         {
185             highestPriorityFound = priority;
186             exceptionToLog = curptr;
187         }
188     }
189 
190     return exceptionToLog;
191 }
192 
193 } // namespace internal
194 
195 } // namespace phosphor::power::regulators::error_logging_utils
196