blob: 4b3916e0847f0e7d30cbf069a09fd638da13cd68 [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>
George Liu3fe976c2022-06-21 09:37:04 +08007
8#include <experimental/tuple>
Andrew Geisslerae4c95c2020-05-16 13:58:53 -05009#include <string>
Patrick Williams26dc0bc2022-06-16 17:06:18 -050010#include <tuple>
Gunnar Mills9679d432017-08-03 15:54:43 -050011
12namespace phosphor
13{
14namespace dbus
15{
16namespace monitoring
17{
18
Matt Spinler3c5318d2018-02-19 14:03:05 -060019/** @struct ToString
20 * @brief Convert numbers to strings
21 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070022template <typename T>
23struct ToString
Matt Spinler3c5318d2018-02-19 14:03:05 -060024{
25 static auto op(T&& value)
26 {
27 return std::to_string(std::forward<T>(value));
28 }
29};
30
Patrick Venture3d6d3182018-08-31 09:33:09 -070031template <>
32struct ToString<std::string>
Matt Spinler3c5318d2018-02-19 14:03:05 -060033{
34 static auto op(const std::string& value)
35 {
36 return value;
37 }
38};
39
Gunnar Mills9679d432017-08-03 15:54:43 -050040/** @class ElogBase
41 * @brief Elog callback implementation.
42 *
43 * The elog callback logs the elog and
44 * elog metadata.
45 */
46class ElogBase : public Callback
47{
Brad Bishopd1eac882018-03-29 10:34:05 -040048 public:
49 ElogBase(const ElogBase&) = delete;
50 ElogBase(ElogBase&&) = default;
51 ElogBase& operator=(const ElogBase&) = delete;
52 ElogBase& operator=(ElogBase&&) = default;
53 virtual ~ElogBase() = default;
54 ElogBase() : Callback()
George Liu3fe976c2022-06-21 09:37:04 +080055 {}
Gunnar Mills9679d432017-08-03 15:54:43 -050056
Brad Bishopd1eac882018-03-29 10:34:05 -040057 /** @brief Callback interface implementation. */
58 void operator()(Context ctx) override;
Gunnar Mills9679d432017-08-03 15:54:43 -050059
Brad Bishopd1eac882018-03-29 10:34:05 -040060 private:
61 /** @brief Delegate type specific calls to subclasses. */
62 virtual void log() const = 0;
Gunnar Mills9679d432017-08-03 15:54:43 -050063};
64
Gunnar Mills30474cf2017-08-11 09:38:54 -050065namespace detail
66{
67
68/** @class CallElog
69 * @brief Provide explicit call forwarding to phosphor::logging::report.
70 *
71 * @tparam T - Error log type
72 * @tparam Args - Metadata fields types.
73 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070074template <typename T, typename... Args>
75struct CallElog
Gunnar Mills30474cf2017-08-11 09:38:54 -050076{
Brad Bishopd1eac882018-03-29 10:34:05 -040077 static void op(Args&&... args)
Gunnar Mills30474cf2017-08-11 09:38:54 -050078 {
79 phosphor::logging::report<T>(std::forward<Args>(args)...);
80 }
81};
82
83} // namespace detail
Gunnar Mills9679d432017-08-03 15:54:43 -050084
85/** @class Elog
86 * @brief C++ type specific logic for the elog callback.
Gunnar Mills30474cf2017-08-11 09:38:54 -050087 * The elog callback logs the elog and elog metadata.
Gunnar Mills9679d432017-08-03 15:54:43 -050088 *
89 * @tparam T - Error log type
Gunnar Mills30474cf2017-08-11 09:38:54 -050090 * @tparam Args - Metadata fields types.
91 * @param[in] arguments - Metadata fields to be added to the error log
Gunnar Mills9679d432017-08-03 15:54:43 -050092 */
Patrick Venture3d6d3182018-08-31 09:33:09 -070093template <typename T, typename... Args>
94class Elog : public ElogBase
Gunnar Mills9679d432017-08-03 15:54:43 -050095{
Brad Bishopd1eac882018-03-29 10:34:05 -040096 public:
97 Elog(const Elog&) = delete;
98 Elog(Elog&&) = default;
99 Elog& operator=(const Elog&) = delete;
100 Elog& operator=(Elog&&) = default;
101 ~Elog() = default;
102 Elog(Args&&... arguments) :
103 ElogBase(), args(std::forward<Args>(arguments)...)
George Liu3fe976c2022-06-21 09:37:04 +0800104 {}
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)
George Liu3fe976c2022-06-21 09:37:04 +0800153 {}
Matt Spinler3c5318d2018-02-19 14:03:05 -0600154
Brad Bishopd1eac882018-03-29 10:34:05 -0400155 /**
156 * @brief Callback interface implementation that
157 * creates an error log
158 */
159 void operator()(Context ctx) override
160 {
Marri Devender Raoee4c6eb2018-04-19 05:51:35 -0500161 if (ctx == Context::START)
162 {
163 // No action should be taken as this call back is being called from
164 // daemon Startup.
165 return;
166 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400167 auto data = captureMetadata();
168
169 phosphor::logging::report<errorType>(metadataType(data.c_str()));
170 }
171
172 private:
173 /**
174 * @brief Builds a metadata string with property information
175 *
176 * Finds all of the properties in the index that have
177 * their condition pass/fail fields (get<resultIndex>(storage))
178 * set to true, and then packs those paths, names, and values
179 * into a metadata string that looks like:
180 *
181 * |path1:name1=value1|path2:name2=value2|...
182 *
183 * @return The metadata string
184 */
185 std::string captureMetadata()
186 {
187 std::string metadata{'|'};
188
189 for (const auto& n : index)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600190 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400191 const auto& storage = std::get<storageIndex>(n.second).get();
192 const auto& result = std::get<resultIndex>(storage);
Matt Spinler3c5318d2018-02-19 14:03:05 -0600193
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500194 if (result.has_value() && std::any_cast<bool>(result))
Brad Bishopd1eac882018-03-29 10:34:05 -0400195 {
196 const auto& path = std::get<pathIndex>(n.first).get();
197 const auto& propertyName =
198 std::get<propertyIndex>(n.first).get();
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500199 auto value = ToString<propertyType>::op(
200 std::any_cast<propertyType>(std::get<valueIndex>(storage)));
Brad Bishopd1eac882018-03-29 10:34:05 -0400201
202 metadata += path + ":" + propertyName + '=' + value + '|';
203 }
Matt Spinler3c5318d2018-02-19 14:03:05 -0600204 }
205
Brad Bishopd1eac882018-03-29 10:34:05 -0400206 return metadata;
207 };
Matt Spinler3c5318d2018-02-19 14:03:05 -0600208};
209
Gunnar Mills30474cf2017-08-11 09:38:54 -0500210/** @brief Argument type deduction for constructing Elog instances.
211 *
212 * @tparam T - Error log type
213 * @tparam Args - Metadata fields types.
214 * @param[in] arguments - Metadata fields to be added to the error log
215 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700216template <typename T, typename... Args>
217auto makeElog(Args&&... arguments)
Gunnar Mills30474cf2017-08-11 09:38:54 -0500218{
Brad Bishopd1eac882018-03-29 10:34:05 -0400219 return std::make_unique<Elog<T, Args...>>(std::forward<Args>(arguments)...);
Gunnar Mills30474cf2017-08-11 09:38:54 -0500220}
221
Gunnar Mills9679d432017-08-03 15:54:43 -0500222} // namespace monitoring
223} // namespace dbus
224} // namespace phosphor