blob: 24a4582095a006c8282a18a942acfb33956999e8 [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>
Andrew Geisslerae4c95c2020-05-16 13:58:53 -05007#include <string>
Patrick Williams26dc0bc2022-06-16 17:06:18 -05008#include <tuple>
Gunnar Mills9679d432017-08-03 15:54:43 -05009
10namespace phosphor
11{
12namespace dbus
13{
14namespace monitoring
15{
16
Matt Spinler3c5318d2018-02-19 14:03:05 -060017/** @struct ToString
18 * @brief Convert numbers to strings
19 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070020template <typename T>
21struct ToString
Matt Spinler3c5318d2018-02-19 14:03:05 -060022{
23 static auto op(T&& value)
24 {
25 return std::to_string(std::forward<T>(value));
26 }
27};
28
Patrick Venture3d6d3182018-08-31 09:33:09 -070029template <>
30struct ToString<std::string>
Matt Spinler3c5318d2018-02-19 14:03:05 -060031{
32 static auto op(const std::string& value)
33 {
34 return value;
35 }
36};
37
Gunnar Mills9679d432017-08-03 15:54:43 -050038/** @class ElogBase
39 * @brief Elog callback implementation.
40 *
41 * The elog callback logs the elog and
42 * elog metadata.
43 */
44class ElogBase : public Callback
45{
Brad Bishopd1eac882018-03-29 10:34:05 -040046 public:
47 ElogBase(const ElogBase&) = delete;
48 ElogBase(ElogBase&&) = default;
49 ElogBase& operator=(const ElogBase&) = delete;
50 ElogBase& operator=(ElogBase&&) = default;
51 virtual ~ElogBase() = default;
52 ElogBase() : Callback()
53 {
54 }
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;
101 Elog(Args&&... arguments) :
102 ElogBase(), args(std::forward<Args>(arguments)...)
103 {
104 }
Gunnar Mills9679d432017-08-03 15:54:43 -0500105
Brad Bishopd1eac882018-03-29 10:34:05 -0400106 private:
107 /** @brief elog interface implementation. */
108 void log() const override
109 {
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500110 std::apply(detail::CallElog<T, Args...>::op, std::tuple_cat(args));
Brad Bishopd1eac882018-03-29 10:34:05 -0400111 }
112 std::tuple<Args...> args;
Gunnar Mills9679d432017-08-03 15:54:43 -0500113};
114
Matt Spinler3c5318d2018-02-19 14:03:05 -0600115/**
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 */
Brad Bishopd1eac882018-03-29 10:34:05 -0400141template <typename errorType, typename metadataType, typename propertyType>
Matt Spinler3c5318d2018-02-19 14:03:05 -0600142class ElogWithMetadataCapture : public IndexedCallback
143{
Brad Bishopd1eac882018-03-29 10:34:05 -0400144 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 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600155
Brad Bishopd1eac882018-03-29 10:34:05 -0400156 /**
157 * @brief Callback interface implementation that
158 * creates an error log
159 */
160 void operator()(Context ctx) override
161 {
Marri Devender Raoee4c6eb2018-04-19 05:51:35 -0500162 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 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400168 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)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600191 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400192 const auto& storage = std::get<storageIndex>(n.second).get();
193 const auto& result = std::get<resultIndex>(storage);
Matt Spinler3c5318d2018-02-19 14:03:05 -0600194
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500195 if (result.has_value() && std::any_cast<bool>(result))
Brad Bishopd1eac882018-03-29 10:34:05 -0400196 {
197 const auto& path = std::get<pathIndex>(n.first).get();
198 const auto& propertyName =
199 std::get<propertyIndex>(n.first).get();
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500200 auto value = ToString<propertyType>::op(
201 std::any_cast<propertyType>(std::get<valueIndex>(storage)));
Brad Bishopd1eac882018-03-29 10:34:05 -0400202
203 metadata += path + ":" + propertyName + '=' + value + '|';
204 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600205 }
206
Brad Bishopd1eac882018-03-29 10:34:05 -0400207 return metadata;
208 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600209};
210
Gunnar Mills30474cf2017-08-11 09:38:54 -0500211/** @brief Argument type deduction for constructing Elog instances.
212 *
213 * @tparam T - Error log type
214 * @tparam Args - Metadata fields types.
215 * @param[in] arguments - Metadata fields to be added to the error log
216 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700217template <typename T, typename... Args>
218auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500219{
Brad Bishopd1eac882018-03-29 10:34:05 -0400220 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500221}
222
Gunnar Mills9679d432017-08-03 15:54:43 -0500223} // namespace monitoring
224} // namespace dbus
225} // namespace phosphor