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