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