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<sdbusplus::exception_t, T>::value,
133 "T must be a descendant of sdbusplus::exception_t");
134 return details::commit(T::errName);
135 }
136
137 /** @fn commit()
138 * @brief Create an error log entry based on journal
139 * entry with a specified MSG_ID. This override accepts error level.
140 * @param[in] level - level of the error
141 *
142 * @return The entry ID
143 */
144 template <typename T>
commit(Entry::Level level)145 uint32_t commit(Entry::Level level)
146 {
147 // Validate if the exception is derived from sdbusplus::exception.
148 static_assert(std::is_base_of<sdbusplus::exception_t, T>::value,
149 "T must be a descendant of sdbusplus::exception_t");
150 return details::commit(T::errName, level);
151 }
152
153 /** @fn elog()
154 * @brief Create a journal log entry based on predefined
155 * error log information
156 * @tparam T - Error log type
157 * @param[in] i_args - Metadata fields to be added to the journal entry
158 */
159 template <typename T, typename... Args>
elog(Args...i_args)160 [[noreturn]] void elog(Args... i_args)
161 {
162 // Validate if the exception is derived from sdbusplus::exception.
163 static_assert(std::is_base_of<sdbusplus::exception_t, T>::value,
164 "T must be a descendant of sdbusplus::exception_t");
165
166 // Validate the caller passed in the required parameters
167 static_assert(
168 std::is_same<typename details::map_exception_type_t<T>::metadata_types,
169 std::tuple<details::deduce_entry_type_t<Args>...>>::value,
170 "You are not passing in required arguments for this error");
171
172 log<details::map_exception_type_t<T>::L>(
173 T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
174
175 // Now throw an exception for this error
176 throw T();
177 }
178
179 /** @fn report()
180 * @brief Create a journal log entry based on predefined
181 * error log information and commit the error
182 * @tparam T - exception
183 * @param[in] i_args - Metadata fields to be added to the journal entry
184 *
185 * @return The entry ID
186 */
187 template <typename T, typename... Args>
report(Args...i_args)188 uint32_t report(Args... i_args)
189 {
190 // validate if the exception is derived from sdbusplus::exception.
191 static_assert(std::is_base_of<sdbusplus::exception_t, T>::value,
192 "T must be a descendant of sdbusplus::exception_t");
193
194 // Validate the caller passed in the required parameters
195 static_assert(
196 std::is_same<typename details::map_exception_type_t<T>::metadata_types,
197 std::tuple<details::deduce_entry_type_t<Args>...>>::value,
198 "You are not passing in required arguments for this error");
199
200 log<details::map_exception_type_t<T>::L>(
201 T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
202
203 return commit<T>();
204 }
205
206 /** @fn report()
207 * @brief Create a journal log entry based on predefined
208 * error log information and commit the error. Accepts error
209 * level.
210 * @tparam T - exception
211 * @param[in] level - level of the error
212 * @param[in] i_args - Metadata fields to be added to the journal entry
213 *
214 * @return The entry ID
215 */
216 template <typename T, typename... Args>
report(Entry::Level level,Args...i_args)217 uint32_t report(Entry::Level level, Args... i_args)
218 {
219 // validate if the exception is derived from sdbusplus::exception.
220 static_assert(std::is_base_of<sdbusplus::exception_t, T>::value,
221 "T must be a descendant of sdbusplus::exception_t");
222
223 // Validate the caller passed in the required parameters
224 static_assert(
225 std::is_same<typename details::map_exception_type_t<T>::metadata_types,
226 std::tuple<details::deduce_entry_type_t<Args>...>>::value,
227 "You are not passing in required arguments for this error");
228
229 log<details::map_exception_type_t<T>::L>(
230 T::errDesc, details::deduce_entry_type<Args>{i_args}.get()...);
231
232 return commit<T>(level);
233 }
234
235 } // namespace logging
236
237 } // namespace phosphor
238