xref: /openbmc/phosphor-dbus-monitor/src/elog.hpp (revision c5fe26a60b7a5f1c3c1a08d9cf2da71467356798)
19679d43eSGunnar Mills #pragma once
23d6d3182SPatrick Venture #include "callback.hpp"
33d6d3182SPatrick Venture 
49679d43eSGunnar Mills #include <phosphor-logging/elog-errors.hpp>
59679d43eSGunnar Mills #include <phosphor-logging/elog.hpp>
69679d43eSGunnar Mills #include <sdbusplus/exception.hpp>
73fe976ccSGeorge Liu 
83fe976ccSGeorge Liu #include <experimental/tuple>
9ae4c95c6SAndrew Geissler #include <string>
1026dc0bcbSPatrick Williams #include <tuple>
119679d43eSGunnar Mills 
129679d43eSGunnar Mills namespace phosphor
139679d43eSGunnar Mills {
149679d43eSGunnar Mills namespace dbus
159679d43eSGunnar Mills {
169679d43eSGunnar Mills namespace monitoring
179679d43eSGunnar Mills {
189679d43eSGunnar Mills 
193c5318d8SMatt Spinler /** @struct ToString
203c5318d8SMatt Spinler  * @brief Convert numbers to strings
213c5318d8SMatt Spinler  */
223d6d3182SPatrick Venture template <typename T>
233d6d3182SPatrick Venture struct ToString
243c5318d8SMatt Spinler {
opphosphor::dbus::monitoring::ToString253c5318d8SMatt Spinler     static auto op(T&& value)
263c5318d8SMatt Spinler     {
273c5318d8SMatt Spinler         return std::to_string(std::forward<T>(value));
283c5318d8SMatt Spinler     }
293c5318d8SMatt Spinler };
303c5318d8SMatt Spinler 
313d6d3182SPatrick Venture template <>
323d6d3182SPatrick Venture struct ToString<std::string>
333c5318d8SMatt Spinler {
opphosphor::dbus::monitoring::ToString343c5318d8SMatt Spinler     static auto op(const std::string& value)
353c5318d8SMatt Spinler     {
363c5318d8SMatt Spinler         return value;
373c5318d8SMatt Spinler     }
383c5318d8SMatt Spinler };
393c5318d8SMatt Spinler 
409679d43eSGunnar Mills /** @class ElogBase
419679d43eSGunnar Mills  *  @brief Elog callback implementation.
429679d43eSGunnar Mills  *
439679d43eSGunnar Mills  *  The elog callback logs the elog and
449679d43eSGunnar Mills  *  elog metadata.
459679d43eSGunnar Mills  */
469679d43eSGunnar Mills class ElogBase : public Callback
479679d43eSGunnar Mills {
489679d43eSGunnar Mills   public:
499679d43eSGunnar Mills     ElogBase(const ElogBase&) = delete;
509679d43eSGunnar Mills     ElogBase(ElogBase&&) = default;
519679d43eSGunnar Mills     ElogBase& operator=(const ElogBase&) = delete;
529679d43eSGunnar Mills     ElogBase& operator=(ElogBase&&) = default;
539679d43eSGunnar Mills     virtual ~ElogBase() = default;
ElogBase()54*c5fe26a6SPatrick Williams     ElogBase() : Callback() {}
559679d43eSGunnar Mills 
569679d43eSGunnar Mills     /** @brief Callback interface implementation. */
57a45e086dSRatan Gupta     void operator()(Context ctx) override;
589679d43eSGunnar Mills 
599679d43eSGunnar Mills   private:
609679d43eSGunnar Mills     /** @brief Delegate type specific calls to subclasses. */
619679d43eSGunnar Mills     virtual void log() const = 0;
629679d43eSGunnar Mills };
639679d43eSGunnar Mills 
6430474cf5SGunnar Mills namespace detail
6530474cf5SGunnar Mills {
6630474cf5SGunnar Mills 
6730474cf5SGunnar Mills /** @class CallElog
6830474cf5SGunnar Mills  *  @brief Provide explicit call forwarding to phosphor::logging::report.
6930474cf5SGunnar Mills  *
7030474cf5SGunnar Mills  *  @tparam T - Error log type
7130474cf5SGunnar Mills  *  @tparam Args - Metadata fields types.
7230474cf5SGunnar Mills  */
733d6d3182SPatrick Venture template <typename T, typename... Args>
743d6d3182SPatrick Venture struct CallElog
7530474cf5SGunnar Mills {
opphosphor::dbus::monitoring::detail::CallElog7630474cf5SGunnar Mills     static void op(Args&&... args)
7730474cf5SGunnar Mills     {
7830474cf5SGunnar Mills         phosphor::logging::report<T>(std::forward<Args>(args)...);
7930474cf5SGunnar Mills     }
8030474cf5SGunnar Mills };
8130474cf5SGunnar Mills 
8230474cf5SGunnar Mills } // namespace detail
839679d43eSGunnar Mills 
849679d43eSGunnar Mills /** @class Elog
859679d43eSGunnar Mills  *  @brief C++ type specific logic for the elog callback.
8630474cf5SGunnar Mills  *         The elog callback logs the elog and elog metadata.
879679d43eSGunnar Mills  *
889679d43eSGunnar Mills  *  @tparam T - Error log type
8930474cf5SGunnar Mills  *  @tparam Args - Metadata fields types.
9030474cf5SGunnar Mills  *  @param[in] arguments - Metadata fields to be added to the error log
919679d43eSGunnar Mills  */
923d6d3182SPatrick Venture template <typename T, typename... Args>
933d6d3182SPatrick Venture class Elog : public ElogBase
949679d43eSGunnar Mills {
959679d43eSGunnar Mills   public:
969679d43eSGunnar Mills     Elog(const Elog&) = delete;
979679d43eSGunnar Mills     Elog(Elog&&) = default;
989679d43eSGunnar Mills     Elog& operator=(const Elog&) = delete;
999679d43eSGunnar Mills     Elog& operator=(Elog&&) = default;
1009679d43eSGunnar Mills     ~Elog() = default;
Elog(Args &&...arguments)101ecef1191SGeorge Liu     explicit Elog(Args&&... arguments) :
102d1eac88dSBrad Bishop         ElogBase(), args(std::forward<Args>(arguments)...)
1033fe976ccSGeorge Liu     {}
1049679d43eSGunnar Mills 
1059679d43eSGunnar Mills   private:
1069679d43eSGunnar Mills     /** @brief elog interface implementation. */
log() const1079679d43eSGunnar Mills     void log() const override
1089679d43eSGunnar Mills     {
10926dc0bcbSPatrick Williams         std::apply(detail::CallElog<T, Args...>::op, std::tuple_cat(args));
1109679d43eSGunnar Mills     }
11130474cf5SGunnar Mills     std::tuple<Args...> args;
1129679d43eSGunnar Mills };
1139679d43eSGunnar Mills 
1143c5318d8SMatt Spinler /**
1153c5318d8SMatt Spinler  * @class ElogWithMetadataCapture
1163c5318d8SMatt Spinler  *
1173c5318d8SMatt Spinler  * @brief A callback class that will save the paths, names, and
1183c5318d8SMatt Spinler  *       current values of certain properties in the metadata of the
1193c5318d8SMatt Spinler  *       error log it creates.
1203c5318d8SMatt Spinler  *
1213c5318d8SMatt Spinler  * The intended use case of this class is to create an error log with
1223c5318d8SMatt Spinler  * metadata that includes the property names and values that caused
1233c5318d8SMatt Spinler  * the condition to issue this callback.  When the condition ran, it had
1243c5318d8SMatt Spinler  * set the pass/fail field on each property it checked in the properties'
1253c5318d8SMatt Spinler  * entries in the Storage array.  This class then looks at those pass/fail
1263c5318d8SMatt Spinler  * fields to see which properties to log.
1273c5318d8SMatt Spinler  *
1283c5318d8SMatt Spinler  * Note that it's OK if different conditions and callbacks share the same
1293c5318d8SMatt Spinler  * properties because everything runs serially, so another condition can't
1303c5318d8SMatt Spinler  * touch those pass/fail fields until all of the first condition's callbacks
1313c5318d8SMatt Spinler  * are done.
1323c5318d8SMatt Spinler  *
1333c5318d8SMatt Spinler  * This class requires that the error log created only have 1 metadata field,
1343c5318d8SMatt Spinler  * and it must take a string.
1353c5318d8SMatt Spinler  *
1363c5318d8SMatt Spinler  * @tparam errorType - Error log type
1373c5318d8SMatt Spinler  * @tparam metadataType - The metadata to use
1383c5318d8SMatt Spinler  * @tparam propertyType - The data type of the captured properties
1393c5318d8SMatt Spinler  */
140d1eac88dSBrad Bishop template <typename errorType, typename metadataType, typename propertyType>
1413c5318d8SMatt Spinler class ElogWithMetadataCapture : public IndexedCallback
1423c5318d8SMatt Spinler {
1433c5318d8SMatt Spinler   public:
1443c5318d8SMatt Spinler     ElogWithMetadataCapture() = delete;
1453c5318d8SMatt Spinler     ElogWithMetadataCapture(const ElogWithMetadataCapture&) = delete;
1463c5318d8SMatt Spinler     ElogWithMetadataCapture(ElogWithMetadataCapture&&) = default;
147d1eac88dSBrad Bishop     ElogWithMetadataCapture& operator=(const ElogWithMetadataCapture&) = delete;
148d1eac88dSBrad Bishop     ElogWithMetadataCapture& operator=(ElogWithMetadataCapture&&) = default;
1493c5318d8SMatt Spinler     virtual ~ElogWithMetadataCapture() = default;
ElogWithMetadataCapture(const PropertyIndex & index)150d1eac88dSBrad Bishop     explicit ElogWithMetadataCapture(const PropertyIndex& index) :
151d1eac88dSBrad Bishop         IndexedCallback(index)
1523fe976ccSGeorge Liu     {}
1533c5318d8SMatt Spinler 
1543c5318d8SMatt Spinler     /**
1553c5318d8SMatt Spinler      * @brief Callback interface implementation that
1563c5318d8SMatt Spinler      *        creates an error log
1573c5318d8SMatt Spinler      */
operator ()(Context ctx)1583c5318d8SMatt Spinler     void operator()(Context ctx) override
1593c5318d8SMatt Spinler     {
160ee4c6ebfSMarri Devender Rao         if (ctx == Context::START)
161ee4c6ebfSMarri Devender Rao         {
162ee4c6ebfSMarri Devender Rao             // No action should be taken as this call back is being called from
163ee4c6ebfSMarri Devender Rao             // daemon Startup.
164ee4c6ebfSMarri Devender Rao             return;
165ee4c6ebfSMarri Devender Rao         }
1663c5318d8SMatt Spinler         auto data = captureMetadata();
1673c5318d8SMatt Spinler 
168d1eac88dSBrad Bishop         phosphor::logging::report<errorType>(metadataType(data.c_str()));
1693c5318d8SMatt Spinler     }
1703c5318d8SMatt Spinler 
1713c5318d8SMatt Spinler   private:
1723c5318d8SMatt Spinler     /**
1733c5318d8SMatt Spinler      * @brief Builds a metadata string with property information
1743c5318d8SMatt Spinler      *
1753c5318d8SMatt Spinler      * Finds all of the properties in the index that have
1761abcb06bSMatt Spinler      * their condition pass/fail fields (get<resultIndex>(storage))
1773c5318d8SMatt Spinler      * set to true, and then packs those paths, names, and values
1783c5318d8SMatt Spinler      * into a metadata string that looks like:
1793c5318d8SMatt Spinler      *
1803c5318d8SMatt Spinler      * |path1:name1=value1|path2:name2=value2|...
1813c5318d8SMatt Spinler      *
1823c5318d8SMatt Spinler      * @return The metadata string
1833c5318d8SMatt Spinler      */
captureMetadata()1843c5318d8SMatt Spinler     std::string captureMetadata()
1853c5318d8SMatt Spinler     {
1863c5318d8SMatt Spinler         std::string metadata{'|'};
1873c5318d8SMatt Spinler 
1883c5318d8SMatt Spinler         for (const auto& n : index)
1893c5318d8SMatt Spinler         {
1901abcb06bSMatt Spinler             const auto& storage = std::get<storageIndex>(n.second).get();
1911abcb06bSMatt Spinler             const auto& result = std::get<resultIndex>(storage);
1923c5318d8SMatt Spinler 
19326dc0bcbSPatrick Williams             if (result.has_value() && std::any_cast<bool>(result))
1943c5318d8SMatt Spinler             {
1951abcb06bSMatt Spinler                 const auto& path = std::get<pathIndex>(n.first).get();
196d1eac88dSBrad Bishop                 const auto& propertyName =
197d1eac88dSBrad Bishop                     std::get<propertyIndex>(n.first).get();
19826dc0bcbSPatrick Williams                 auto value = ToString<propertyType>::op(
19926dc0bcbSPatrick Williams                     std::any_cast<propertyType>(std::get<valueIndex>(storage)));
2003c5318d8SMatt Spinler 
201d1eac88dSBrad Bishop                 metadata += path + ":" + propertyName + '=' + value + '|';
2023c5318d8SMatt Spinler             }
2033c5318d8SMatt Spinler         }
2043c5318d8SMatt Spinler 
2053c5318d8SMatt Spinler         return metadata;
2063c5318d8SMatt Spinler     };
2073c5318d8SMatt Spinler };
2083c5318d8SMatt Spinler 
20930474cf5SGunnar Mills /** @brief Argument type deduction for constructing Elog instances.
21030474cf5SGunnar Mills  *
21130474cf5SGunnar Mills  *  @tparam T - Error log type
21230474cf5SGunnar Mills  *  @tparam Args - Metadata fields types.
21330474cf5SGunnar Mills  *  @param[in] arguments - Metadata fields to be added to the error log
21430474cf5SGunnar Mills  */
2153d6d3182SPatrick Venture template <typename T, typename... Args>
makeElog(Args &&...arguments)2163d6d3182SPatrick Venture auto makeElog(Args&&... arguments)
21730474cf5SGunnar Mills {
218d1eac88dSBrad Bishop     return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
21930474cf5SGunnar Mills }
22030474cf5SGunnar Mills 
2219679d43eSGunnar Mills } // namespace monitoring
2229679d43eSGunnar Mills } // namespace dbus
2239679d43eSGunnar Mills } // namespace phosphor
224