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