blob: a7e4e1c1010b5e3dfdb614fc25e6e1fb8fa42aeb [file] [log] [blame]
Gunnar Mills9679d432017-08-03 15:54:43 -05001#pragma once
Patrick Venture3d6d3182018-08-31 09:33:09 -07002#include "callback.hpp"
3
Gunnar Mills9679d432017-08-03 15:54:43 -05004#include <phosphor-logging/elog-errors.hpp>
5#include <phosphor-logging/elog.hpp>
Gunnar Mills9679d432017-08-03 15:54:43 -05006#include <sdbusplus/exception.hpp>
George Liu3fe976c2022-06-21 09:37:04 +08007
8#include <experimental/tuple>
Andrew Geisslerae4c95c2020-05-16 13:58:53 -05009#include <string>
Patrick Williams26dc0bc2022-06-16 17:06:18 -050010#include <tuple>
Gunnar Mills9679d432017-08-03 15:54:43 -050011
12namespace phosphor
13{
14namespace dbus
15{
16namespace monitoring
17{
18
Matt Spinler3c5318d2018-02-19 14:03:05 -060019/** @struct ToString
20 * @brief Convert numbers to strings
21 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070022template <typename T>
23struct ToString
Matt Spinler3c5318d2018-02-19 14:03:05 -060024{
25 static auto op(T&& value)
26 {
27 return std::to_string(std::forward<T>(value));
28 }
29};
30
Patrick Venture3d6d3182018-08-31 09:33:09 -070031template <>
32struct ToString<std::string>
Matt Spinler3c5318d2018-02-19 14:03:05 -060033{
34 static auto op(const std::string& value)
35 {
36 return value;
37 }
38};
39
Gunnar Mills9679d432017-08-03 15:54:43 -050040/** @class ElogBase
41 * @brief Elog callback implementation.
42 *
43 * The elog callback logs the elog and
44 * elog metadata.
45 */
46class ElogBase : public Callback
47{
Brad Bishopd1eac882018-03-29 10:34:05 -040048 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 Williamsc5fe26a2023-05-10 07:50:25 -050054 ElogBase() : Callback() {}
Gunnar Mills9679d432017-08-03 15:54:43 -050055
Brad Bishopd1eac882018-03-29 10:34:05 -040056 /** @brief Callback interface implementation. */
57 void operator()(Context ctx) override;
Gunnar Mills9679d432017-08-03 15:54:43 -050058
Brad Bishopd1eac882018-03-29 10:34:05 -040059 private:
60 /** @brief Delegate type specific calls to subclasses. */
61 virtual void log() const = 0;
Gunnar Mills9679d432017-08-03 15:54:43 -050062};
63
Gunnar Mills30474cf2017-08-11 09:38:54 -050064namespace 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 Venture3d6d3182018-08-31 09:33:09 -070073template <typename T, typename... Args>
74struct CallElog
Gunnar Mills30474cf2017-08-11 09:38:54 -050075{
Brad Bishopd1eac882018-03-29 10:34:05 -040076 static void op(Args&&... args)
Gunnar Mills30474cf2017-08-11 09:38:54 -050077 {
78 phosphor::logging::report<T>(std::forward<Args>(args)...);
79 }
80};
81
82} // namespace detail
Gunnar Mills9679d432017-08-03 15:54:43 -050083
84/** @class Elog
85 * @brief C++ type specific logic for the elog callback.
Gunnar Mills30474cf2017-08-11 09:38:54 -050086 * The elog callback logs the elog and elog metadata.
Gunnar Mills9679d432017-08-03 15:54:43 -050087 *
88 * @tparam T - Error log type
Gunnar Mills30474cf2017-08-11 09:38:54 -050089 * @tparam Args - Metadata fields types.
90 * @param[in] arguments - Metadata fields to be added to the error log
Gunnar Mills9679d432017-08-03 15:54:43 -050091 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070092template <typename T, typename... Args>
93class Elog : public ElogBase
Gunnar Mills9679d432017-08-03 15:54:43 -050094{
Brad Bishopd1eac882018-03-29 10:34:05 -040095 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 Liuecef1192022-07-07 08:59:12 +0800101 explicit Elog(Args&&... arguments) :
Brad Bishopd1eac882018-03-29 10:34:05 -0400102 ElogBase(), args(std::forward<Args>(arguments)...)
George Liu3fe976c2022-06-21 09:37:04 +0800103 {}
Gunnar Mills9679d432017-08-03 15:54:43 -0500104
Brad Bishopd1eac882018-03-29 10:34:05 -0400105 private:
106 /** @brief elog interface implementation. */
107 void log() const override
108 {
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500109 std::apply(detail::CallElog<T, Args...>::op, std::tuple_cat(args));
Brad Bishopd1eac882018-03-29 10:34:05 -0400110 }
111 std::tuple<Args...> args;
Gunnar Mills9679d432017-08-03 15:54:43 -0500112};
113
Matt Spinler3c5318d2018-02-19 14:03:05 -0600114/**
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 Bishopd1eac882018-03-29 10:34:05 -0400140template <typename errorType, typename metadataType, typename propertyType>
Matt Spinler3c5318d2018-02-19 14:03:05 -0600141class ElogWithMetadataCapture : public IndexedCallback
142{
Brad Bishopd1eac882018-03-29 10:34:05 -0400143 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 Liu3fe976c2022-06-21 09:37:04 +0800152 {}
Matt Spinler3c5318d2018-02-19 14:03:05 -0600153
Brad Bishopd1eac882018-03-29 10:34:05 -0400154 /**
155 * @brief Callback interface implementation that
156 * creates an error log
157 */
158 void operator()(Context ctx) override
159 {
Marri Devender Raoee4c6eb2018-04-19 05:51:35 -0500160 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 Bishopd1eac882018-03-29 10:34:05 -0400166 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 Spinler3c5318d2018-02-19 14:03:05 -0600189 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400190 const auto& storage = std::get<storageIndex>(n.second).get();
191 const auto& result = std::get<resultIndex>(storage);
Matt Spinler3c5318d2018-02-19 14:03:05 -0600192
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500193 if (result.has_value() && std::any_cast<bool>(result))
Brad Bishopd1eac882018-03-29 10:34:05 -0400194 {
195 const auto& path = std::get<pathIndex>(n.first).get();
196 const auto& propertyName =
197 std::get<propertyIndex>(n.first).get();
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500198 auto value = ToString<propertyType>::op(
199 std::any_cast<propertyType>(std::get<valueIndex>(storage)));
Brad Bishopd1eac882018-03-29 10:34:05 -0400200
201 metadata += path + ":" + propertyName + '=' + value + '|';
202 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600203 }
204
Brad Bishopd1eac882018-03-29 10:34:05 -0400205 return metadata;
206 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600207};
208
Gunnar Mills30474cf2017-08-11 09:38:54 -0500209/** @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 Venture3d6d3182018-08-31 09:33:09 -0700215template <typename T, typename... Args>
216auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500217{
Brad Bishopd1eac882018-03-29 10:34:05 -0400218 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500219}
220
Gunnar Mills9679d432017-08-03 15:54:43 -0500221} // namespace monitoring
222} // namespace dbus
223} // namespace phosphor