blob: 6e46b77c354b7ed4a95a4b0620cd91b3158bee18 [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
4#include <experimental/tuple>
Gunnar Mills9679d432017-08-03 15:54:43 -05005#include <phosphor-logging/elog-errors.hpp>
6#include <phosphor-logging/elog.hpp>
Gunnar Mills9679d432017-08-03 15:54:43 -05007#include <sdbusplus/exception.hpp>
Andrew Geisslerae4c95c2020-05-16 13:58:53 -05008#include <string>
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 {
110 std::experimental::apply(detail::CallElog<T, Args...>::op,
111 std::tuple_cat(args));
112 }
113 std::tuple<Args...> args;
Gunnar Mills9679d432017-08-03 15:54:43 -0500114};
115
Matt Spinler3c5318d2018-02-19 14:03:05 -0600116/**
117 * @class ElogWithMetadataCapture
118 *
119 * @brief A callback class that will save the paths, names, and
120 * current values of certain properties in the metadata of the
121 * error log it creates.
122 *
123 * The intended use case of this class is to create an error log with
124 * metadata that includes the property names and values that caused
125 * the condition to issue this callback. When the condition ran, it had
126 * set the pass/fail field on each property it checked in the properties'
127 * entries in the Storage array. This class then looks at those pass/fail
128 * fields to see which properties to log.
129 *
130 * Note that it's OK if different conditions and callbacks share the same
131 * properties because everything runs serially, so another condition can't
132 * touch those pass/fail fields until all of the first condition's callbacks
133 * are done.
134 *
135 * This class requires that the error log created only have 1 metadata field,
136 * and it must take a string.
137 *
138 * @tparam errorType - Error log type
139 * @tparam metadataType - The metadata to use
140 * @tparam propertyType - The data type of the captured properties
141 */
Brad Bishopd1eac882018-03-29 10:34:05 -0400142template <typename errorType, typename metadataType, typename propertyType>
Matt Spinler3c5318d2018-02-19 14:03:05 -0600143class ElogWithMetadataCapture : public IndexedCallback
144{
Brad Bishopd1eac882018-03-29 10:34:05 -0400145 public:
146 ElogWithMetadataCapture() = delete;
147 ElogWithMetadataCapture(const ElogWithMetadataCapture&) = delete;
148 ElogWithMetadataCapture(ElogWithMetadataCapture&&) = default;
149 ElogWithMetadataCapture& operator=(const ElogWithMetadataCapture&) = delete;
150 ElogWithMetadataCapture& operator=(ElogWithMetadataCapture&&) = default;
151 virtual ~ElogWithMetadataCapture() = default;
152 explicit ElogWithMetadataCapture(const PropertyIndex& index) :
153 IndexedCallback(index)
154 {
155 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600156
Brad Bishopd1eac882018-03-29 10:34:05 -0400157 /**
158 * @brief Callback interface implementation that
159 * creates an error log
160 */
161 void operator()(Context ctx) override
162 {
Marri Devender Raoee4c6eb2018-04-19 05:51:35 -0500163 if (ctx == Context::START)
164 {
165 // No action should be taken as this call back is being called from
166 // daemon Startup.
167 return;
168 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400169 auto data = captureMetadata();
170
171 phosphor::logging::report<errorType>(metadataType(data.c_str()));
172 }
173
174 private:
175 /**
176 * @brief Builds a metadata string with property information
177 *
178 * Finds all of the properties in the index that have
179 * their condition pass/fail fields (get<resultIndex>(storage))
180 * set to true, and then packs those paths, names, and values
181 * into a metadata string that looks like:
182 *
183 * |path1:name1=value1|path2:name2=value2|...
184 *
185 * @return The metadata string
186 */
187 std::string captureMetadata()
188 {
189 std::string metadata{'|'};
190
191 for (const auto& n : index)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600192 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400193 const auto& storage = std::get<storageIndex>(n.second).get();
194 const auto& result = std::get<resultIndex>(storage);
Matt Spinler3c5318d2018-02-19 14:03:05 -0600195
Brad Bishopd1eac882018-03-29 10:34:05 -0400196 if (!result.empty() && any_ns::any_cast<bool>(result))
197 {
198 const auto& path = std::get<pathIndex>(n.first).get();
199 const auto& propertyName =
200 std::get<propertyIndex>(n.first).get();
201 auto value =
202 ToString<propertyType>::op(any_ns::any_cast<propertyType>(
203 std::get<valueIndex>(storage)));
204
205 metadata += path + ":" + propertyName + '=' + value + '|';
206 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600207 }
208
Brad Bishopd1eac882018-03-29 10:34:05 -0400209 return metadata;
210 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600211};
212
Gunnar Mills30474cf2017-08-11 09:38:54 -0500213/** @brief Argument type deduction for constructing Elog instances.
214 *
215 * @tparam T - Error log type
216 * @tparam Args - Metadata fields types.
217 * @param[in] arguments - Metadata fields to be added to the error log
218 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700219template <typename T, typename... Args>
220auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500221{
Brad Bishopd1eac882018-03-29 10:34:05 -0400222 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500223}
224
Gunnar Mills9679d432017-08-03 15:54:43 -0500225} // namespace monitoring
226} // namespace dbus
227} // namespace phosphor