xref: /openbmc/phosphor-logging/lib/include/phosphor-logging/elog.hpp (revision 4e1456e428ac23d579659fdeb5a8ef823a533e69)
1 #pragma once
2 #include "xyz/openbmc_project/Logging/Entry/server.hpp"
3 
4 #include <phosphor-logging/log.hpp>
5 #include <sdbusplus/exception.hpp>
6 
7 #include <tuple>
8 #include <utility>
9 
10 namespace phosphor
11 {
12 
13 namespace logging
14 {
15 
16 using namespace sdbusplus::server::xyz::openbmc_project::logging;
17 
18 /**
19  * @brief Structure used by callers to indicate they want to use the last value
20  *        put in the journal for input parameter.
21  */
22 template <typename T>
23 struct prev_entry
24 {
25     using type = T;
26 };
27 
28 namespace details
29 {
30 /**
31  * @brief Used to return the generated tuple for the error code meta data
32  *
33  * The prev_entry (above) and deduce_entry_type structures below are used
34  * to verify at compile time the required parameters have been passed to
35  * the elog interface and then to forward on the appropriate tuple to the
36  * log interface.
37  */
38 template <typename T>
39 struct deduce_entry_type
40 {
41     using type = T;
getphosphor::logging::details::deduce_entry_type42     auto get()
43     {
44         return value._entry;
45     }
46 
47     T value;
48 };
49 
50 /**
51  * @brief Used to return an empty tuple for prev_entry parameters
52  *
53  * This is done so we can still call the log() interface with the variable
54  * arg parameters to elog.  The log() interface will simply ignore the empty
55  * tuples which is what we want for prev_entry parameters.
56  */
57 template <typename T>
58 struct deduce_entry_type<prev_entry<T>>
59 {
60     using type = T;
getphosphor::logging::details::deduce_entry_type61     auto get()
62     {
63         return std::make_tuple();
64     }
65 
66     prev_entry<T> value;
67 };
68 
69 /**
70  * @brief Typedef for above structure usage
71  */
72 template <typename T>
73 using deduce_entry_type_t = typename deduce_entry_type<T>::type;
74 
75 /**
76  * @brief Used to map an sdbusplus error to a phosphor-logging error type
77  *
78  * Users log errors via the sdbusplus error name, and the execption that's
79  * thrown is the corresponding sdbusplus exception. However, there's a need
80  * to map the sdbusplus error name to the phosphor-logging error name, in order
81  * to verify the error metadata at compile-time.
82  */
83 template <typename T>
84 struct map_exception_type
85 {
86     using type = T;
87 };
88 
89 /**
90  * @brief Typedef for above structure usage
91  */
92 template <typename T>
93 using map_exception_type_t = typename map_exception_type<T>::type;
94 
95 /** @fn commit()
96  *  @brief Create an error log entry based on journal
97  *          entry with a specified exception name
98  *  @param[in] name - name of the error exception
99  *
100  *  @return The entry ID
101  */
102 uint32_t commit(const char* name);
103 
104 /** @fn commit() - override that accepts error level
105  *
106  *  @return The entry ID
107  */
108 uint32_t commit(const char* name, Entry::Level level);
109 
110 } // namespace details
111 
112 /** @fn commit()
113  *  \deprecated use commit<T>()
114  *  @brief Create an error log entry based on journal
115  *          entry with a specified MSG_ID
116  *  @param[in] name - name of the error exception
117  *
118  *  @return The entry ID
119  */
120 uint32_t commit(std::string&& name);
121 
122 /** @fn commit()
123  *  @brief Create an error log entry based on journal
124  *          entry with a specified MSG_ID
125  *
126  *  @return The entry ID
127  */
128 template <typename T>
commit()129 uint32_t commit()
130 {
131     // Validate if the exception is derived from sdbusplus::exception.
132     static_assert(std::is_base_of_v<sdbusplus::exception_t, T>,
133                   "T must be a descendant of sdbusplus::exception_t");
134     static_assert(
135         !std::is_base_of_v<sdbusplus::exception::generated_event<T>, T>,
136         "T must NOT be an sdbusplus::generated_event");
137 
138     return details::commit(T::errName);
139 }
140 
141 /** @fn commit()
142  *  @brief Create an error log entry based on journal
143  *         entry with a specified MSG_ID. This override accepts error level.
144  *  @param[in] level - level of the error
145  *
146  *  @return The entry ID
147  */
148 template <typename T>
commit(Entry::Level level)149 uint32_t commit(Entry::Level level)
150 {
151     // Validate if the exception is derived from sdbusplus::exception.
152     static_assert(std::is_base_of_v<sdbusplus::exception_t, T>,
153                   "T must be a descendant of sdbusplus::exception_t");
154     static_assert(
155         !std::is_base_of_v<sdbusplus::exception::generated_event<T>, T>,
156         "T must NOT be an sdbusplus::generated_event");
157 
158     return details::commit(T::errName, level);
159 }
160 
161 /** @fn elog()
162  *  @brief Create a journal log entry based on predefined
163  *          error log information
164  *  @tparam T - Error log type
165  *  @param[in] i_args - Metadata fields to be added to the journal entry
166  */
167 template <typename T, typename... Args>
elog(Args...i_args)168 [[noreturn]] void elog(Args... i_args)
169 {
170     // Validate if the exception is derived from sdbusplus::exception.
171     static_assert(std::is_base_of_v<sdbusplus::exception_t, T>,
172                   "T must be a descendant of sdbusplus::exception_t");
173     static_assert(
174         !std::is_base_of_v<sdbusplus::exception::generated_event<T>, T>,
175         "T must NOT be an sdbusplus::generated_event");
176 
177     // Validate the caller passed in the required parameters
178     static_assert(std::is_same_v<
179                       typename details::map_exception_type_t<T>::metadata_types,
180                       std::tuple<details::deduce_entry_type_t<Args>...>>,
181                   "You are not passing in required arguments for this error");
182 
183     log<details::map_exception_type_t<T>::L>(
184         T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
185 
186     // Now throw an exception for this error
187     throw T();
188 }
189 
190 /** @fn report()
191  *  @brief Create a journal log entry based on predefined
192  *         error log information and commit the error
193  *  @tparam T - exception
194  *  @param[in] i_args - Metadata fields to be added to the journal entry
195  *
196  *  @return The entry ID
197  */
198 template <typename T, typename... Args>
report(Args...i_args)199 uint32_t report(Args... i_args)
200 {
201     // validate if the exception is derived from sdbusplus::exception.
202     static_assert(std::is_base_of_v<sdbusplus::exception_t, T>,
203                   "T must be a descendant of sdbusplus::exception_t");
204     static_assert(
205         !std::is_base_of_v<sdbusplus::exception::generated_event<T>, T>,
206         "T must NOT be an sdbusplus::generated_event");
207 
208     // Validate the caller passed in the required parameters
209     static_assert(std::is_same_v<
210                       typename details::map_exception_type_t<T>::metadata_types,
211                       std::tuple<details::deduce_entry_type_t<Args>...>>,
212                   "You are not passing in required arguments for this error");
213 
214     log<details::map_exception_type_t<T>::L>(
215         T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
216 
217     return commit<T>();
218 }
219 
220 /** @fn report()
221  *  @brief Create a journal log entry based on predefined
222  *         error log information and commit the error. Accepts error
223  *         level.
224  *  @tparam T - exception
225  *  @param[in] level - level of the error
226  *  @param[in] i_args - Metadata fields to be added to the journal entry
227  *
228  *  @return The entry ID
229  */
230 template <typename T, typename... Args>
report(Entry::Level level,Args...i_args)231 uint32_t report(Entry::Level level, Args... i_args)
232 {
233     // validate if the exception is derived from sdbusplus::exception.
234     static_assert(std::is_base_of_v<sdbusplus::exception_t, T>,
235                   "T must be a descendant of sdbusplus::exception_t");
236     static_assert(
237         !std::is_base_of_v<sdbusplus::exception::generated_event<T>, T>,
238         "T must NOT be an sdbusplus::generated_event");
239 
240     // Validate the caller passed in the required parameters
241     static_assert(std::is_same_v<
242                       typename details::map_exception_type_t<T>::metadata_types,
243                       std::tuple<details::deduce_entry_type_t<Args>...>>,
244                   "You are not passing in required arguments for this error");
245 
246     log<details::map_exception_type_t<T>::L>(
247         T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
248 
249     return commit<T>(level);
250 }
251 
252 } // namespace logging
253 
254 } // namespace phosphor
255