blob: 3f8ae3b8bb2bd52aa91b28ff3785431aa5ad6f22 [file] [log] [blame]
Gunnar Mills9679d432017-08-03 15:54:43 -05001#pragma once
2#include <phosphor-logging/elog-errors.hpp>
3#include <phosphor-logging/elog.hpp>
4#include "callback.hpp"
5#include <sdbusplus/exception.hpp>
Gunnar Mills30474cf2017-08-11 09:38:54 -05006#include <experimental/tuple>
Gunnar Mills9679d432017-08-03 15:54:43 -05007
8namespace phosphor
9{
10namespace dbus
11{
12namespace monitoring
13{
14
Matt Spinler3c5318d2018-02-19 14:03:05 -060015/** @struct ToString
16 * @brief Convert numbers to strings
17 */
18template <typename T> struct ToString
19{
20 static auto op(T&& value)
21 {
22 return std::to_string(std::forward<T>(value));
23 }
24};
25
26template <> struct ToString<std::string>
27{
28 static auto op(const std::string& value)
29 {
30 return value;
31 }
32};
33
Gunnar Mills9679d432017-08-03 15:54:43 -050034/** @class ElogBase
35 * @brief Elog callback implementation.
36 *
37 * The elog callback logs the elog and
38 * elog metadata.
39 */
40class ElogBase : public Callback
41{
42 public:
43 ElogBase(const ElogBase&) = delete;
44 ElogBase(ElogBase&&) = default;
45 ElogBase& operator=(const ElogBase&) = delete;
46 ElogBase& operator=(ElogBase&&) = default;
47 virtual ~ElogBase() = default;
48 ElogBase() :
Gunnar Mills30474cf2017-08-11 09:38:54 -050049 Callback() {}
Gunnar Mills9679d432017-08-03 15:54:43 -050050
51 /** @brief Callback interface implementation. */
Ratan Guptaa45e0862018-02-21 19:03:13 +053052 void operator()(Context ctx) override;
Gunnar Mills9679d432017-08-03 15:54:43 -050053
54 private:
55 /** @brief Delegate type specific calls to subclasses. */
56 virtual void log() const = 0;
57};
58
Gunnar Mills30474cf2017-08-11 09:38:54 -050059namespace detail
60{
61
62/** @class CallElog
63 * @brief Provide explicit call forwarding to phosphor::logging::report.
64 *
65 * @tparam T - Error log type
66 * @tparam Args - Metadata fields types.
67 */
68template <typename T, typename ...Args>
69struct CallElog
70{
71 static void op(Args&& ...args)
72 {
73 phosphor::logging::report<T>(std::forward<Args>(args)...);
74 }
75};
76
77} // namespace detail
Gunnar Mills9679d432017-08-03 15:54:43 -050078
79/** @class Elog
80 * @brief C++ type specific logic for the elog callback.
Gunnar Mills30474cf2017-08-11 09:38:54 -050081 * The elog callback logs the elog and elog metadata.
Gunnar Mills9679d432017-08-03 15:54:43 -050082 *
83 * @tparam T - Error log type
Gunnar Mills30474cf2017-08-11 09:38:54 -050084 * @tparam Args - Metadata fields types.
85 * @param[in] arguments - Metadata fields to be added to the error log
Gunnar Mills9679d432017-08-03 15:54:43 -050086 */
Gunnar Mills30474cf2017-08-11 09:38:54 -050087template <typename T, typename ...Args>
Gunnar Mills9679d432017-08-03 15:54:43 -050088class Elog : public ElogBase
89{
90 public:
91 Elog(const Elog&) = delete;
92 Elog(Elog&&) = default;
93 Elog& operator=(const Elog&) = delete;
94 Elog& operator=(Elog&&) = default;
95 ~Elog() = default;
Gunnar Mills30474cf2017-08-11 09:38:54 -050096 Elog(Args&& ... arguments) :
97 ElogBase(), args(std::forward<Args>(arguments)...) {}
Gunnar Mills9679d432017-08-03 15:54:43 -050098
99 private:
100 /** @brief elog interface implementation. */
101 void log() const override
102 {
Gunnar Mills30474cf2017-08-11 09:38:54 -0500103 std::experimental::apply(
104 detail::CallElog<T, Args...>::op,
105 std::tuple_cat(args));
Gunnar Mills9679d432017-08-03 15:54:43 -0500106 }
Gunnar Mills30474cf2017-08-11 09:38:54 -0500107 std::tuple<Args...> args;
108
Gunnar Mills9679d432017-08-03 15:54:43 -0500109};
110
Matt Spinler3c5318d2018-02-19 14:03:05 -0600111
112/**
113 * @class ElogWithMetadataCapture
114 *
115 * @brief A callback class that will save the paths, names, and
116 * current values of certain properties in the metadata of the
117 * error log it creates.
118 *
119 * The intended use case of this class is to create an error log with
120 * metadata that includes the property names and values that caused
121 * the condition to issue this callback. When the condition ran, it had
122 * set the pass/fail field on each property it checked in the properties'
123 * entries in the Storage array. This class then looks at those pass/fail
124 * fields to see which properties to log.
125 *
126 * Note that it's OK if different conditions and callbacks share the same
127 * properties because everything runs serially, so another condition can't
128 * touch those pass/fail fields until all of the first condition's callbacks
129 * are done.
130 *
131 * This class requires that the error log created only have 1 metadata field,
132 * and it must take a string.
133 *
134 * @tparam errorType - Error log type
135 * @tparam metadataType - The metadata to use
136 * @tparam propertyType - The data type of the captured properties
137 */
138template<typename errorType,
139 typename metadataType,
140 typename propertyType>
141class ElogWithMetadataCapture : public IndexedCallback
142{
143 public:
144 ElogWithMetadataCapture() = delete;
145 ElogWithMetadataCapture(const ElogWithMetadataCapture&) = delete;
146 ElogWithMetadataCapture(ElogWithMetadataCapture&&) = default;
147 ElogWithMetadataCapture& operator=(
148 const ElogWithMetadataCapture&) = delete;
149 ElogWithMetadataCapture& operator=(
150 ElogWithMetadataCapture&&) = default;
151 virtual ~ElogWithMetadataCapture() = default;
152 explicit ElogWithMetadataCapture(
153 const PropertyIndex& index) :
154 IndexedCallback(index) {}
155
156 /**
157 * @brief Callback interface implementation that
158 * creates an error log
159 */
160 void operator()(Context ctx) override
161 {
162 auto data = captureMetadata();
163
164 phosphor::logging::report<errorType>(
165 metadataType(data.c_str()));
166 }
167
168 private:
169
170 /**
171 * @brief Builds a metadata string with property information
172 *
173 * Finds all of the properties in the index that have
174 * their condition pass/fail fields (get<1>(storage))
175 * set to true, and then packs those paths, names, and values
176 * into a metadata string that looks like:
177 *
178 * |path1:name1=value1|path2:name2=value2|...
179 *
180 * @return The metadata string
181 */
182 std::string captureMetadata()
183 {
184 std::string metadata{'|'};
185
186 for (const auto& n : index)
187 {
188 const auto& storage = std::get<2>(n.second).get();
189 const auto& result = std::get<1>(storage);
190
191 if (!result.empty() && any_ns::any_cast<bool>(result))
192 {
193 const auto& path = std::get<0>(n.first).get();
194 const auto& propertyName = std::get<2>(n.first).get();
195 auto value = ToString<propertyType>::op(
196 any_ns::any_cast<propertyType>(
197 std::get<0>(storage)));
198
199 metadata += path + ":" + propertyName +
200 '=' + value + '|';
201 }
202 }
203
204 return metadata;
205 };
206};
207
Gunnar Mills30474cf2017-08-11 09:38:54 -0500208/** @brief Argument type deduction for constructing Elog instances.
209 *
210 * @tparam T - Error log type
211 * @tparam Args - Metadata fields types.
212 * @param[in] arguments - Metadata fields to be added to the error log
213 */
214template <typename T, typename ...Args>
215auto makeElog(Args&& ... arguments)
216{
217 return std::make_unique<Elog<T, Args...>>(
218 std::forward<Args>(arguments)...);
219}
220
Gunnar Mills9679d432017-08-03 15:54:43 -0500221} // namespace monitoring
222} // namespace dbus
223} // namespace phosphor