1 #include "trigger_actions.hpp"
2
3 #include "messages/update_report_ind.hpp"
4 #include "types/trigger_types.hpp"
5 #include "utils/clock.hpp"
6 #include "utils/messanger.hpp"
7 #include "utils/to_short_enum.hpp"
8
9 #include <phosphor-logging/log.hpp>
10
11 #include <ctime>
12 #include <iomanip>
13 #include <sstream>
14
15 namespace action
16 {
17
18 namespace
19 {
timestampToString(Milliseconds timestamp)20 std::string timestampToString(Milliseconds timestamp)
21 {
22 std::time_t t = static_cast<time_t>(
23 std::chrono::duration_cast<std::chrono::seconds>(timestamp).count());
24 std::stringstream ss;
25 ss << std::put_time(std::gmtime(&t), "%FT%T.") << std::setw(3)
26 << std::setfill('0') << timestamp.count() % 1000 << 'Z';
27 return ss.str();
28 }
29 } // namespace
30
31 namespace numeric
32 {
33
getDirection(double value,double threshold)34 static const char* getDirection(double value, double threshold)
35 {
36 if (value < threshold)
37 {
38 return "decreasing";
39 }
40 if (value > threshold)
41 {
42 return "increasing";
43 }
44 throw std::runtime_error("Invalid value");
45 }
46
commit(const std::string & triggerId,const ThresholdName thresholdNameInIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)47 void LogToJournal::commit(
48 const std::string& triggerId, const ThresholdName thresholdNameInIn,
49 const std::string& sensorName, const Milliseconds timestamp,
50 const TriggerValue triggerValue)
51 {
52 double value = std::get<double>(triggerValue);
53 std::string thresholdName = ::numeric::typeToString(type);
54 auto direction = getDirection(value, threshold);
55
56 std::string msg =
57 "Numeric threshold '" + std::string(utils::toShortEnum(thresholdName)) +
58 "' of trigger '" + triggerId + "' is crossed on sensor " + sensorName +
59 ", recorded value: " + std::to_string(value) +
60 ", crossing direction: " + std::string(utils::toShortEnum(direction)) +
61 ", timestamp: " + timestampToString(timestamp);
62
63 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
64 }
65
getRedfishMessageId(const double value) const66 const char* LogToRedfishEventLog::getRedfishMessageId(const double value) const
67 {
68 std::string direction(getDirection(value, threshold));
69
70 if (direction == "decreasing")
71 {
72 switch (type)
73 {
74 case ::numeric::Type::upperCritical:
75 return redfish_message_ids::TriggerNumericBelowUpperCritical;
76 case ::numeric::Type::lowerCritical:
77 return redfish_message_ids::TriggerNumericBelowLowerCritical;
78 case ::numeric::Type::upperWarning:
79 return redfish_message_ids::TriggerNumericReadingNormal;
80 case ::numeric::Type::lowerWarning:
81 return redfish_message_ids::TriggerNumericBelowLowerWarning;
82 }
83 }
84
85 if (direction == "increasing")
86 {
87 switch (type)
88 {
89 case ::numeric::Type::upperCritical:
90 return redfish_message_ids::TriggerNumericAboveUpperCritical;
91 case ::numeric::Type::lowerCritical:
92 return redfish_message_ids::TriggerNumericAboveLowerCritical;
93 case ::numeric::Type::upperWarning:
94 return redfish_message_ids::TriggerNumericAboveUpperWarning;
95 case ::numeric::Type::lowerWarning:
96 return redfish_message_ids::TriggerNumericReadingNormal;
97 }
98 }
99
100 throw std::runtime_error("Invalid type");
101 }
102
commit(const std::string & triggerId,const ThresholdName thresholdNameInIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)103 void LogToRedfishEventLog::commit(
104 const std::string& triggerId, const ThresholdName thresholdNameInIn,
105 const std::string& sensorName, const Milliseconds timestamp,
106 const TriggerValue triggerValue)
107 {
108 double value = std::get<double>(triggerValue);
109 auto messageId = getRedfishMessageId(value);
110
111 if (std::string_view(messageId) ==
112 redfish_message_ids::TriggerNumericReadingNormal)
113 {
114 phosphor::logging::log<phosphor::logging::level::INFO>(
115 "Logging numeric trigger action to Redfish Event Log.",
116 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
117 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%s",
118 sensorName.c_str(), value,
119 triggerId.c_str()));
120 }
121 else
122 {
123 phosphor::logging::log<phosphor::logging::level::INFO>(
124 "Logging numeric trigger action to Redfish Event Log.",
125 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
126 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%f,%s",
127 sensorName.c_str(), value, threshold,
128 triggerId.c_str()));
129 }
130 }
131
fillActions(std::vector<std::unique_ptr<interfaces::TriggerAction>> & actionsIf,const std::vector<TriggerAction> & ActionsEnum,::numeric::Type type,double thresholdValue,boost::asio::io_context & ioc,const std::shared_ptr<std::vector<std::string>> & reportIds)132 void fillActions(
133 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
134 const std::vector<TriggerAction>& ActionsEnum, ::numeric::Type type,
135 double thresholdValue, boost::asio::io_context& ioc,
136 const std::shared_ptr<std::vector<std::string>>& reportIds)
137 {
138 actionsIf.reserve(ActionsEnum.size());
139 for (auto actionType : ActionsEnum)
140 {
141 switch (actionType)
142 {
143 case TriggerAction::LogToJournal:
144 {
145 actionsIf.emplace_back(
146 std::make_unique<LogToJournal>(type, thresholdValue));
147 break;
148 }
149 case TriggerAction::LogToRedfishEventLog:
150 {
151 actionsIf.emplace_back(std::make_unique<LogToRedfishEventLog>(
152 type, thresholdValue));
153 break;
154 }
155 case TriggerAction::UpdateReport:
156 {
157 actionsIf.emplace_back(
158 std::make_unique<UpdateReport>(ioc, reportIds));
159 break;
160 }
161 }
162 }
163 }
164
165 } // namespace numeric
166
167 namespace discrete
168 {
169
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)170 void LogToJournal::commit(
171 const std::string& triggerId, const ThresholdName thresholdNameIn,
172 const std::string& sensorName, const Milliseconds timestamp,
173 const TriggerValue triggerValue)
174 {
175 auto value = std::get<std::string>(triggerValue);
176
177 std::string msg =
178 "Discrete condition '" + thresholdNameIn->get() + "' of trigger '" +
179 triggerId + "' is met on sensor " + sensorName +
180 ", recorded value: " + value + ", severity: " +
181 std::string(utils::toShortEnum(utils::enumToString(severity))) +
182 ", timestamp: " + timestampToString(timestamp);
183
184 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
185 }
186
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)187 void LogToRedfishEventLog::commit(
188 const std::string& triggerId, const ThresholdName thresholdNameIn,
189 const std::string& sensorName, const Milliseconds timestamp,
190 const TriggerValue triggerValue)
191 {
192 auto value = std::get<std::string>(triggerValue);
193
194 phosphor::logging::log<phosphor::logging::level::INFO>(
195 "Logging discrete trigger action to Redfish Event Log.",
196 phosphor::logging::entry(
197 "REDFISH_MESSAGE_ID=%s",
198 redfish_message_ids::TriggerDiscreteConditionMet),
199 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s",
200 sensorName.c_str(), value.c_str(),
201 triggerId.c_str()));
202 }
203
fillActions(std::vector<std::unique_ptr<interfaces::TriggerAction>> & actionsIf,const std::vector<TriggerAction> & ActionsEnum,::discrete::Severity severity,boost::asio::io_context & ioc,const std::shared_ptr<std::vector<std::string>> & reportIds)204 void fillActions(
205 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
206 const std::vector<TriggerAction>& ActionsEnum,
207 ::discrete::Severity severity, boost::asio::io_context& ioc,
208 const std::shared_ptr<std::vector<std::string>>& reportIds)
209 {
210 actionsIf.reserve(ActionsEnum.size());
211 for (auto actionType : ActionsEnum)
212 {
213 switch (actionType)
214 {
215 case TriggerAction::LogToJournal:
216 {
217 actionsIf.emplace_back(
218 std::make_unique<LogToJournal>(severity));
219 break;
220 }
221 case TriggerAction::LogToRedfishEventLog:
222 {
223 actionsIf.emplace_back(
224 std::make_unique<LogToRedfishEventLog>());
225 break;
226 }
227 case TriggerAction::UpdateReport:
228 {
229 actionsIf.emplace_back(
230 std::make_unique<UpdateReport>(ioc, reportIds));
231 break;
232 }
233 }
234 }
235 }
236
237 namespace onChange
238 {
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)239 void LogToJournal::commit(
240 const std::string& triggerId, const ThresholdName thresholdNameIn,
241 const std::string& sensorName, const Milliseconds timestamp,
242 const TriggerValue triggerValue)
243 {
244 auto value = triggerValueToString(triggerValue);
245 std::string msg =
246 "Discrete condition 'OnChange' of trigger '" + triggerId +
247 "' is met on sensor: " + sensorName + ", recorded value: " + value +
248 ", timestamp: " + timestampToString(timestamp);
249
250 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
251 }
252
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)253 void LogToRedfishEventLog::commit(
254 const std::string& triggerId, const ThresholdName thresholdNameIn,
255 const std::string& sensorName, const Milliseconds timestamp,
256 const TriggerValue triggerValue)
257 {
258 auto value = triggerValueToString(triggerValue);
259
260 phosphor::logging::log<phosphor::logging::level::INFO>(
261 "Logging onChange discrete trigger action to Redfish Event Log.",
262 phosphor::logging::entry(
263 "REDFISH_MESSAGE_ID=%s",
264 redfish_message_ids::TriggerDiscreteConditionMet),
265 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s",
266 sensorName.c_str(), value.c_str(),
267 triggerId.c_str()));
268 }
269
fillActions(std::vector<std::unique_ptr<interfaces::TriggerAction>> & actionsIf,const std::vector<TriggerAction> & ActionsEnum,boost::asio::io_context & ioc,const std::shared_ptr<std::vector<std::string>> & reportIds)270 void fillActions(
271 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
272 const std::vector<TriggerAction>& ActionsEnum, boost::asio::io_context& ioc,
273 const std::shared_ptr<std::vector<std::string>>& reportIds)
274 {
275 actionsIf.reserve(ActionsEnum.size());
276 for (auto actionType : ActionsEnum)
277 {
278 switch (actionType)
279 {
280 case TriggerAction::LogToJournal:
281 {
282 actionsIf.emplace_back(std::make_unique<LogToJournal>());
283 break;
284 }
285 case TriggerAction::LogToRedfishEventLog:
286 {
287 actionsIf.emplace_back(
288 std::make_unique<LogToRedfishEventLog>());
289 break;
290 }
291 case TriggerAction::UpdateReport:
292 {
293 actionsIf.emplace_back(
294 std::make_unique<UpdateReport>(ioc, reportIds));
295 break;
296 }
297 }
298 }
299 }
300 } // namespace onChange
301 } // namespace discrete
302
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)303 void UpdateReport::commit(
304 const std::string& triggerId, const ThresholdName thresholdNameIn,
305 const std::string& sensorName, const Milliseconds timestamp,
306 const TriggerValue triggerValue)
307 {
308 if (reportIds->empty())
309 {
310 return;
311 }
312
313 utils::Messanger messanger(ioc);
314 messanger.send(messages::UpdateReportInd{*reportIds});
315 }
316 } // namespace action
317