xref: /openbmc/phosphor-power/phosphor-regulators/src/error_logging_utils.cpp (revision d62367d6b4018179fb53c596860e511979447d2e)
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 using ConfigFileParserError = phosphor::power::util::ConfigFileParserError;
31 
32 namespace phosphor::power::regulators::error_logging_utils
33 {
34 
35 void logError(std::exception_ptr eptr, Entry::Level severity,
36               Services& services)
37 {
38     // Specify empty error history so that all error types will be logged
39     ErrorHistory history{};
40     logError(eptr, severity, services, history);
41 }
42 
43 void logError(std::exception_ptr eptr, Entry::Level severity,
44               Services& services, ErrorHistory& history)
45 {
46     // Check for null exception pointer
47     if (!eptr)
48     {
49         return;
50     }
51 
52     // Get exception to log from specified exception and any nested exceptions
53     std::exception_ptr exceptionToLog = internal::getExceptionToLog(eptr);
54 
55     // Log an error based on the exception
56     ErrorLogging& errorLogging = services.getErrorLogging();
57     Journal& journal = services.getJournal();
58     ErrorType errorType{};
59     try
60     {
61         std::rethrow_exception(exceptionToLog);
62     }
63     catch (const ConfigFileParserError& e)
64     {
65         errorType = ErrorType::configFile;
66         if (!history.wasLogged(errorType))
67         {
68             history.setWasLogged(errorType, true);
69             errorLogging.logConfigFileError(severity, journal);
70         }
71     }
72     catch (const PMBusError& e)
73     {
74         errorType = ErrorType::pmbus;
75         if (!history.wasLogged(errorType))
76         {
77             history.setWasLogged(errorType, true);
78             errorLogging.logPMBusError(severity, journal, e.getInventoryPath());
79         }
80     }
81     catch (const WriteVerificationError& e)
82     {
83         errorType = ErrorType::writeVerification;
84         if (!history.wasLogged(errorType))
85         {
86             history.setWasLogged(errorType, true);
87             errorLogging.logWriteVerificationError(severity, journal,
88                                                    e.getInventoryPath());
89         }
90     }
91     catch (const i2c::I2CException& e)
92     {
93         errorType = ErrorType::i2c;
94         if (!history.wasLogged(errorType))
95         {
96             history.setWasLogged(errorType, true);
97             errorLogging.logI2CError(severity, journal, e.bus, e.addr,
98                                      e.errorCode);
99         }
100     }
101     catch (const sdbusplus::exception_t& e)
102     {
103         errorType = ErrorType::dbus;
104         if (!history.wasLogged(errorType))
105         {
106             history.setWasLogged(errorType, true);
107             errorLogging.logDBusError(severity, journal);
108         }
109     }
110     catch (const std::exception& e)
111     {
112         errorType = ErrorType::internal;
113         if (!history.wasLogged(errorType))
114         {
115             history.setWasLogged(errorType, true);
116             errorLogging.logInternalError(severity, journal);
117         }
118     }
119     catch (...)
120     {
121         errorType = ErrorType::internal;
122         if (!history.wasLogged(errorType))
123         {
124             history.setWasLogged(errorType, true);
125             errorLogging.logInternalError(severity, journal);
126         }
127     }
128 }
129 
130 namespace internal
131 {
132 
133 std::exception_ptr getExceptionToLog(std::exception_ptr eptr)
134 {
135     // Default to selecting the outermost exception
136     std::exception_ptr exceptionToLog{eptr};
137 
138     // Get vector containing this exception and any nested exceptions
139     std::vector<std::exception_ptr> exceptions =
140         exception_utils::getExceptions(eptr);
141 
142     // Define temporary constants for exception priorities
143     const int lowPriority{0}, mediumPriority{1}, highPriority{2};
144 
145     // Loop through the exceptions from innermost to outermost.  Find the
146     // exception with the highest priority.  If there is a tie, select the
147     // outermost exception with that priority.
148     int highestPriorityFound{-1};
149     for (std::exception_ptr curptr : exceptions)
150     {
151         int priority{-1};
152         try
153         {
154             std::rethrow_exception(curptr);
155         }
156         catch (const ConfigFileParserError& e)
157         {
158             priority = highPriority;
159         }
160         catch (const PMBusError& e)
161         {
162             priority = highPriority;
163         }
164         catch (const WriteVerificationError& e)
165         {
166             priority = highPriority;
167         }
168         catch (const i2c::I2CException& e)
169         {
170             priority = highPriority;
171         }
172         catch (const sdbusplus::exception_t& e)
173         {
174             priority = mediumPriority;
175         }
176         catch (const std::exception& e)
177         {
178             priority = lowPriority;
179         }
180         catch (...)
181         {
182             priority = lowPriority;
183         }
184 
185         if (priority >= highestPriorityFound)
186         {
187             highestPriorityFound = priority;
188             exceptionToLog = curptr;
189         }
190     }
191 
192     return exceptionToLog;
193 }
194 
195 } // namespace internal
196 
197 } // namespace phosphor::power::regulators::error_logging_utils
198