blob: d98984c1fd05bf186cfe5c9f1b776977f044594c [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>
8
9namespace phosphor
10{
11namespace dbus
12{
13namespace monitoring
14{
15
Matt Spinler3c5318d2018-02-19 14:03:05 -060016/** @struct ToString
17 * @brief Convert numbers to strings
18 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070019template <typename T>
20struct ToString
Matt Spinler3c5318d2018-02-19 14:03:05 -060021{
22 static auto op(T&& value)
23 {
24 return std::to_string(std::forward<T>(value));
25 }
26};
27
Patrick Venture3d6d3182018-08-31 09:33:09 -070028template <>
29struct ToString<std::string>
Matt Spinler3c5318d2018-02-19 14:03:05 -060030{
31 static auto op(const std::string& value)
32 {
33 return value;
34 }
35};
36
Gunnar Mills9679d432017-08-03 15:54:43 -050037/** @class ElogBase
38 * @brief Elog callback implementation.
39 *
40 * The elog callback logs the elog and
41 * elog metadata.
42 */
43class ElogBase : public Callback
44{
Brad Bishopd1eac882018-03-29 10:34:05 -040045 public:
46 ElogBase(const ElogBase&) = delete;
47 ElogBase(ElogBase&&) = default;
48 ElogBase& operator=(const ElogBase&) = delete;
49 ElogBase& operator=(ElogBase&&) = default;
50 virtual ~ElogBase() = default;
51 ElogBase() : Callback()
52 {
53 }
Gunnar Mills9679d432017-08-03 15:54:43 -050054
Brad Bishopd1eac882018-03-29 10:34:05 -040055 /** @brief Callback interface implementation. */
56 void operator()(Context ctx) override;
Gunnar Mills9679d432017-08-03 15:54:43 -050057
Brad Bishopd1eac882018-03-29 10:34:05 -040058 private:
59 /** @brief Delegate type specific calls to subclasses. */
60 virtual void log() const = 0;
Gunnar Mills9679d432017-08-03 15:54:43 -050061};
62
Gunnar Mills30474cf2017-08-11 09:38:54 -050063namespace detail
64{
65
66/** @class CallElog
67 * @brief Provide explicit call forwarding to phosphor::logging::report.
68 *
69 * @tparam T - Error log type
70 * @tparam Args - Metadata fields types.
71 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070072template <typename T, typename... Args>
73struct CallElog
Gunnar Mills30474cf2017-08-11 09:38:54 -050074{
Brad Bishopd1eac882018-03-29 10:34:05 -040075 static void op(Args&&... args)
Gunnar Mills30474cf2017-08-11 09:38:54 -050076 {
77 phosphor::logging::report<T>(std::forward<Args>(args)...);
78 }
79};
80
81} // namespace detail
Gunnar Mills9679d432017-08-03 15:54:43 -050082
83/** @class Elog
84 * @brief C++ type specific logic for the elog callback.
Gunnar Mills30474cf2017-08-11 09:38:54 -050085 * The elog callback logs the elog and elog metadata.
Gunnar Mills9679d432017-08-03 15:54:43 -050086 *
87 * @tparam T - Error log type
Gunnar Mills30474cf2017-08-11 09:38:54 -050088 * @tparam Args - Metadata fields types.
89 * @param[in] arguments - Metadata fields to be added to the error log
Gunnar Mills9679d432017-08-03 15:54:43 -050090 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070091template <typename T, typename... Args>
92class Elog : public ElogBase
Gunnar Mills9679d432017-08-03 15:54:43 -050093{
Brad Bishopd1eac882018-03-29 10:34:05 -040094 public:
95 Elog(const Elog&) = delete;
96 Elog(Elog&&) = default;
97 Elog& operator=(const Elog&) = delete;
98 Elog& operator=(Elog&&) = default;
99 ~Elog() = default;
100 Elog(Args&&... arguments) :
101 ElogBase(), args(std::forward<Args>(arguments)...)
102 {
103 }
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 {
109 std::experimental::apply(detail::CallElog<T, Args...>::op,
110 std::tuple_cat(args));
111 }
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
Brad Bishopd1eac882018-03-29 10:34:05 -0400195 if (!result.empty() && any_ns::any_cast<bool>(result))
196 {
197 const auto& path = std::get<pathIndex>(n.first).get();
198 const auto& propertyName =
199 std::get<propertyIndex>(n.first).get();
200 auto value =
201 ToString<propertyType>::op(any_ns::any_cast<propertyType>(
202 std::get<valueIndex>(storage)));
203
204 metadata += path + ":" + propertyName + '=' + value + '|';
205 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600206 }
207
Brad Bishopd1eac882018-03-29 10:34:05 -0400208 return metadata;
209 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600210};
211
Gunnar Mills30474cf2017-08-11 09:38:54 -0500212/** @brief Argument type deduction for constructing Elog instances.
213 *
214 * @tparam T - Error log type
215 * @tparam Args - Metadata fields types.
216 * @param[in] arguments - Metadata fields to be added to the error log
217 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700218template <typename T, typename... Args>
219auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500220{
Brad Bishopd1eac882018-03-29 10:34:05 -0400221 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500222}
223
Gunnar Mills9679d432017-08-03 15:54:43 -0500224} // namespace monitoring
225} // namespace dbus
226} // namespace phosphor