blob: 24e20097b64ca7847999e425c9fae0f5e38e3f14 [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{
Brad Bishopd1eac882018-03-29 10:34:05 -040042 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() : Callback()
49 {
50 }
Gunnar Mills9679d432017-08-03 15:54:43 -050051
Brad Bishopd1eac882018-03-29 10:34:05 -040052 /** @brief Callback interface implementation. */
53 void operator()(Context ctx) override;
Gunnar Mills9679d432017-08-03 15:54:43 -050054
Brad Bishopd1eac882018-03-29 10:34:05 -040055 private:
56 /** @brief Delegate type specific calls to subclasses. */
57 virtual void log() const = 0;
Gunnar Mills9679d432017-08-03 15:54:43 -050058};
59
Gunnar Mills30474cf2017-08-11 09:38:54 -050060namespace detail
61{
62
63/** @class CallElog
64 * @brief Provide explicit call forwarding to phosphor::logging::report.
65 *
66 * @tparam T - Error log type
67 * @tparam Args - Metadata fields types.
68 */
Brad Bishopd1eac882018-03-29 10:34:05 -040069template <typename T, typename... Args> struct CallElog
Gunnar Mills30474cf2017-08-11 09:38:54 -050070{
Brad Bishopd1eac882018-03-29 10:34:05 -040071 static void op(Args&&... args)
Gunnar Mills30474cf2017-08-11 09:38:54 -050072 {
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 */
Brad Bishopd1eac882018-03-29 10:34:05 -040087template <typename T, typename... Args> class Elog : public ElogBase
Gunnar Mills9679d432017-08-03 15:54:43 -050088{
Brad Bishopd1eac882018-03-29 10:34:05 -040089 public:
90 Elog(const Elog&) = delete;
91 Elog(Elog&&) = default;
92 Elog& operator=(const Elog&) = delete;
93 Elog& operator=(Elog&&) = default;
94 ~Elog() = default;
95 Elog(Args&&... arguments) :
96 ElogBase(), args(std::forward<Args>(arguments)...)
97 {
98 }
Gunnar Mills9679d432017-08-03 15:54:43 -050099
Brad Bishopd1eac882018-03-29 10:34:05 -0400100 private:
101 /** @brief elog interface implementation. */
102 void log() const override
103 {
104 std::experimental::apply(detail::CallElog<T, Args...>::op,
105 std::tuple_cat(args));
106 }
107 std::tuple<Args...> args;
Gunnar Mills9679d432017-08-03 15:54:43 -0500108};
109
Matt Spinler3c5318d2018-02-19 14:03:05 -0600110/**
111 * @class ElogWithMetadataCapture
112 *
113 * @brief A callback class that will save the paths, names, and
114 * current values of certain properties in the metadata of the
115 * error log it creates.
116 *
117 * The intended use case of this class is to create an error log with
118 * metadata that includes the property names and values that caused
119 * the condition to issue this callback. When the condition ran, it had
120 * set the pass/fail field on each property it checked in the properties'
121 * entries in the Storage array. This class then looks at those pass/fail
122 * fields to see which properties to log.
123 *
124 * Note that it's OK if different conditions and callbacks share the same
125 * properties because everything runs serially, so another condition can't
126 * touch those pass/fail fields until all of the first condition's callbacks
127 * are done.
128 *
129 * This class requires that the error log created only have 1 metadata field,
130 * and it must take a string.
131 *
132 * @tparam errorType - Error log type
133 * @tparam metadataType - The metadata to use
134 * @tparam propertyType - The data type of the captured properties
135 */
Brad Bishopd1eac882018-03-29 10:34:05 -0400136template <typename errorType, typename metadataType, typename propertyType>
Matt Spinler3c5318d2018-02-19 14:03:05 -0600137class ElogWithMetadataCapture : public IndexedCallback
138{
Brad Bishopd1eac882018-03-29 10:34:05 -0400139 public:
140 ElogWithMetadataCapture() = delete;
141 ElogWithMetadataCapture(const ElogWithMetadataCapture&) = delete;
142 ElogWithMetadataCapture(ElogWithMetadataCapture&&) = default;
143 ElogWithMetadataCapture& operator=(const ElogWithMetadataCapture&) = delete;
144 ElogWithMetadataCapture& operator=(ElogWithMetadataCapture&&) = default;
145 virtual ~ElogWithMetadataCapture() = default;
146 explicit ElogWithMetadataCapture(const PropertyIndex& index) :
147 IndexedCallback(index)
148 {
149 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600150
Brad Bishopd1eac882018-03-29 10:34:05 -0400151 /**
152 * @brief Callback interface implementation that
153 * creates an error log
154 */
155 void operator()(Context ctx) override
156 {
Marri Devender Raoee4c6eb2018-04-19 05:51:35 -0500157 if (ctx == Context::START)
158 {
159 // No action should be taken as this call back is being called from
160 // daemon Startup.
161 return;
162 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400163 auto data = captureMetadata();
164
165 phosphor::logging::report<errorType>(metadataType(data.c_str()));
166 }
167
168 private:
169 /**
170 * @brief Builds a metadata string with property information
171 *
172 * Finds all of the properties in the index that have
173 * their condition pass/fail fields (get<resultIndex>(storage))
174 * set to true, and then packs those paths, names, and values
175 * into a metadata string that looks like:
176 *
177 * |path1:name1=value1|path2:name2=value2|...
178 *
179 * @return The metadata string
180 */
181 std::string captureMetadata()
182 {
183 std::string metadata{'|'};
184
185 for (const auto& n : index)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600186 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400187 const auto& storage = std::get<storageIndex>(n.second).get();
188 const auto& result = std::get<resultIndex>(storage);
Matt Spinler3c5318d2018-02-19 14:03:05 -0600189
Brad Bishopd1eac882018-03-29 10:34:05 -0400190 if (!result.empty() && any_ns::any_cast<bool>(result))
191 {
192 const auto& path = std::get<pathIndex>(n.first).get();
193 const auto& propertyName =
194 std::get<propertyIndex>(n.first).get();
195 auto value =
196 ToString<propertyType>::op(any_ns::any_cast<propertyType>(
197 std::get<valueIndex>(storage)));
198
199 metadata += path + ":" + propertyName + '=' + value + '|';
200 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600201 }
202
Brad Bishopd1eac882018-03-29 10:34:05 -0400203 return metadata;
204 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600205};
206
Gunnar Mills30474cf2017-08-11 09:38:54 -0500207/** @brief Argument type deduction for constructing Elog instances.
208 *
209 * @tparam T - Error log type
210 * @tparam Args - Metadata fields types.
211 * @param[in] arguments - Metadata fields to be added to the error log
212 */
Brad Bishopd1eac882018-03-29 10:34:05 -0400213template <typename T, typename... Args> auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500214{
Brad Bishopd1eac882018-03-29 10:34:05 -0400215 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500216}
217
Gunnar Mills9679d432017-08-03 15:54:43 -0500218} // namespace monitoring
219} // namespace dbus
220} // namespace phosphor