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