Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 1 | #pragma once |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 2 | #include "callback.hpp" |
| 3 | |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 4 | #include <phosphor-logging/elog-errors.hpp> |
| 5 | #include <phosphor-logging/elog.hpp> |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 6 | #include <sdbusplus/exception.hpp> |
George Liu | 3fe976c | 2022-06-21 09:37:04 +0800 | [diff] [blame] | 7 | |
| 8 | #include <experimental/tuple> |
Andrew Geissler | ae4c95c | 2020-05-16 13:58:53 -0500 | [diff] [blame] | 9 | #include <string> |
Patrick Williams | 26dc0bc | 2022-06-16 17:06:18 -0500 | [diff] [blame] | 10 | #include <tuple> |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 11 | |
| 12 | namespace phosphor |
| 13 | { |
| 14 | namespace dbus |
| 15 | { |
| 16 | namespace monitoring |
| 17 | { |
| 18 | |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 19 | /** @struct ToString |
| 20 | * @brief Convert numbers to strings |
| 21 | */ |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 22 | template <typename T> |
| 23 | struct ToString |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 24 | { |
| 25 | static auto op(T&& value) |
| 26 | { |
| 27 | return std::to_string(std::forward<T>(value)); |
| 28 | } |
| 29 | }; |
| 30 | |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 31 | template <> |
| 32 | struct ToString<std::string> |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 33 | { |
| 34 | static auto op(const std::string& value) |
| 35 | { |
| 36 | return value; |
| 37 | } |
| 38 | }; |
| 39 | |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 40 | /** @class ElogBase |
| 41 | * @brief Elog callback implementation. |
| 42 | * |
| 43 | * The elog callback logs the elog and |
| 44 | * elog metadata. |
| 45 | */ |
| 46 | class ElogBase : public Callback |
| 47 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 48 | public: |
| 49 | ElogBase(const ElogBase&) = delete; |
| 50 | ElogBase(ElogBase&&) = default; |
| 51 | ElogBase& operator=(const ElogBase&) = delete; |
| 52 | ElogBase& operator=(ElogBase&&) = default; |
| 53 | virtual ~ElogBase() = default; |
Patrick Williams | c5fe26a | 2023-05-10 07:50:25 -0500 | [diff] [blame] | 54 | ElogBase() : Callback() {} |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 55 | |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 56 | /** @brief Callback interface implementation. */ |
| 57 | void operator()(Context ctx) override; |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 58 | |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 59 | private: |
| 60 | /** @brief Delegate type specific calls to subclasses. */ |
| 61 | virtual void log() const = 0; |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 62 | }; |
| 63 | |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 64 | namespace detail |
| 65 | { |
| 66 | |
| 67 | /** @class CallElog |
| 68 | * @brief Provide explicit call forwarding to phosphor::logging::report. |
| 69 | * |
| 70 | * @tparam T - Error log type |
| 71 | * @tparam Args - Metadata fields types. |
| 72 | */ |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 73 | template <typename T, typename... Args> |
| 74 | struct CallElog |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 75 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 76 | static void op(Args&&... args) |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 77 | { |
| 78 | phosphor::logging::report<T>(std::forward<Args>(args)...); |
| 79 | } |
| 80 | }; |
| 81 | |
| 82 | } // namespace detail |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 83 | |
| 84 | /** @class Elog |
| 85 | * @brief C++ type specific logic for the elog callback. |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 86 | * The elog callback logs the elog and elog metadata. |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 87 | * |
| 88 | * @tparam T - Error log type |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 89 | * @tparam Args - Metadata fields types. |
| 90 | * @param[in] arguments - Metadata fields to be added to the error log |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 91 | */ |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 92 | template <typename T, typename... Args> |
| 93 | class Elog : public ElogBase |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 94 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 95 | public: |
| 96 | Elog(const Elog&) = delete; |
| 97 | Elog(Elog&&) = default; |
| 98 | Elog& operator=(const Elog&) = delete; |
| 99 | Elog& operator=(Elog&&) = default; |
| 100 | ~Elog() = default; |
George Liu | ecef119 | 2022-07-07 08:59:12 +0800 | [diff] [blame] | 101 | explicit Elog(Args&&... arguments) : |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 102 | ElogBase(), args(std::forward<Args>(arguments)...) |
George Liu | 3fe976c | 2022-06-21 09:37:04 +0800 | [diff] [blame] | 103 | {} |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 104 | |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 105 | private: |
| 106 | /** @brief elog interface implementation. */ |
| 107 | void log() const override |
| 108 | { |
Patrick Williams | 26dc0bc | 2022-06-16 17:06:18 -0500 | [diff] [blame] | 109 | std::apply(detail::CallElog<T, Args...>::op, std::tuple_cat(args)); |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 110 | } |
| 111 | std::tuple<Args...> args; |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 112 | }; |
| 113 | |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 114 | /** |
| 115 | * @class ElogWithMetadataCapture |
| 116 | * |
| 117 | * @brief A callback class that will save the paths, names, and |
| 118 | * current values of certain properties in the metadata of the |
| 119 | * error log it creates. |
| 120 | * |
| 121 | * The intended use case of this class is to create an error log with |
| 122 | * metadata that includes the property names and values that caused |
| 123 | * the condition to issue this callback. When the condition ran, it had |
| 124 | * set the pass/fail field on each property it checked in the properties' |
| 125 | * entries in the Storage array. This class then looks at those pass/fail |
| 126 | * fields to see which properties to log. |
| 127 | * |
| 128 | * Note that it's OK if different conditions and callbacks share the same |
| 129 | * properties because everything runs serially, so another condition can't |
| 130 | * touch those pass/fail fields until all of the first condition's callbacks |
| 131 | * are done. |
| 132 | * |
| 133 | * This class requires that the error log created only have 1 metadata field, |
| 134 | * and it must take a string. |
| 135 | * |
| 136 | * @tparam errorType - Error log type |
| 137 | * @tparam metadataType - The metadata to use |
| 138 | * @tparam propertyType - The data type of the captured properties |
| 139 | */ |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 140 | template <typename errorType, typename metadataType, typename propertyType> |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 141 | class ElogWithMetadataCapture : public IndexedCallback |
| 142 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 143 | public: |
| 144 | ElogWithMetadataCapture() = delete; |
| 145 | ElogWithMetadataCapture(const ElogWithMetadataCapture&) = delete; |
| 146 | ElogWithMetadataCapture(ElogWithMetadataCapture&&) = default; |
| 147 | ElogWithMetadataCapture& operator=(const ElogWithMetadataCapture&) = delete; |
| 148 | ElogWithMetadataCapture& operator=(ElogWithMetadataCapture&&) = default; |
| 149 | virtual ~ElogWithMetadataCapture() = default; |
| 150 | explicit ElogWithMetadataCapture(const PropertyIndex& index) : |
| 151 | IndexedCallback(index) |
George Liu | 3fe976c | 2022-06-21 09:37:04 +0800 | [diff] [blame] | 152 | {} |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 153 | |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 154 | /** |
| 155 | * @brief Callback interface implementation that |
| 156 | * creates an error log |
| 157 | */ |
| 158 | void operator()(Context ctx) override |
| 159 | { |
Marri Devender Rao | ee4c6eb | 2018-04-19 05:51:35 -0500 | [diff] [blame] | 160 | if (ctx == Context::START) |
| 161 | { |
| 162 | // No action should be taken as this call back is being called from |
| 163 | // daemon Startup. |
| 164 | return; |
| 165 | } |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 166 | auto data = captureMetadata(); |
| 167 | |
| 168 | phosphor::logging::report<errorType>(metadataType(data.c_str())); |
| 169 | } |
| 170 | |
| 171 | private: |
| 172 | /** |
| 173 | * @brief Builds a metadata string with property information |
| 174 | * |
| 175 | * Finds all of the properties in the index that have |
| 176 | * their condition pass/fail fields (get<resultIndex>(storage)) |
| 177 | * set to true, and then packs those paths, names, and values |
| 178 | * into a metadata string that looks like: |
| 179 | * |
| 180 | * |path1:name1=value1|path2:name2=value2|... |
| 181 | * |
| 182 | * @return The metadata string |
| 183 | */ |
| 184 | std::string captureMetadata() |
| 185 | { |
| 186 | std::string metadata{'|'}; |
| 187 | |
| 188 | for (const auto& n : index) |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 189 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 190 | const auto& storage = std::get<storageIndex>(n.second).get(); |
| 191 | const auto& result = std::get<resultIndex>(storage); |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 192 | |
Patrick Williams | 26dc0bc | 2022-06-16 17:06:18 -0500 | [diff] [blame] | 193 | if (result.has_value() && std::any_cast<bool>(result)) |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 194 | { |
| 195 | const auto& path = std::get<pathIndex>(n.first).get(); |
| 196 | const auto& propertyName = |
| 197 | std::get<propertyIndex>(n.first).get(); |
Patrick Williams | 26dc0bc | 2022-06-16 17:06:18 -0500 | [diff] [blame] | 198 | auto value = ToString<propertyType>::op( |
| 199 | std::any_cast<propertyType>(std::get<valueIndex>(storage))); |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 200 | |
| 201 | metadata += path + ":" + propertyName + '=' + value + '|'; |
| 202 | } |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 203 | } |
| 204 | |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 205 | return metadata; |
| 206 | }; |
Matt Spinler | 3c5318d | 2018-02-19 14:03:05 -0600 | [diff] [blame] | 207 | }; |
| 208 | |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 209 | /** @brief Argument type deduction for constructing Elog instances. |
| 210 | * |
| 211 | * @tparam T - Error log type |
| 212 | * @tparam Args - Metadata fields types. |
| 213 | * @param[in] arguments - Metadata fields to be added to the error log |
| 214 | */ |
Patrick Venture | 3d6d318 | 2018-08-31 09:33:09 -0700 | [diff] [blame] | 215 | template <typename T, typename... Args> |
| 216 | auto makeElog(Args&&... arguments) |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 217 | { |
Brad Bishop | d1eac88 | 2018-03-29 10:34:05 -0400 | [diff] [blame] | 218 | return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...); |
Gunnar Mills | 30474cf | 2017-08-11 09:38:54 -0500 | [diff] [blame] | 219 | } |
| 220 | |
Gunnar Mills | 9679d43 | 2017-08-03 15:54:43 -0500 | [diff] [blame] | 221 | } // namespace monitoring |
| 222 | } // namespace dbus |
| 223 | } // namespace phosphor |