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 (messageId == redfish_message_ids::TriggerNumericReadingNormal)
112 {
113 phosphor::logging::log<phosphor::logging::level::INFO>(
114 "Logging numeric trigger action to Redfish Event Log.",
115 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
116 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%s",
117 sensorName.c_str(), value,
118 triggerId.c_str()));
119 }
120 else
121 {
122 phosphor::logging::log<phosphor::logging::level::INFO>(
123 "Logging numeric trigger action to Redfish Event Log.",
124 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
125 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%f,%s",
126 sensorName.c_str(), value, threshold,
127 triggerId.c_str()));
128 }
129 }
130
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)131 void fillActions(
132 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
133 const std::vector<TriggerAction>& ActionsEnum, ::numeric::Type type,
134 double thresholdValue, boost::asio::io_context& ioc,
135 const std::shared_ptr<std::vector<std::string>>& reportIds)
136 {
137 actionsIf.reserve(ActionsEnum.size());
138 for (auto actionType : ActionsEnum)
139 {
140 switch (actionType)
141 {
142 case TriggerAction::LogToJournal:
143 {
144 actionsIf.emplace_back(
145 std::make_unique<LogToJournal>(type, thresholdValue));
146 break;
147 }
148 case TriggerAction::LogToRedfishEventLog:
149 {
150 actionsIf.emplace_back(std::make_unique<LogToRedfishEventLog>(
151 type, thresholdValue));
152 break;
153 }
154 case TriggerAction::UpdateReport:
155 {
156 actionsIf.emplace_back(
157 std::make_unique<UpdateReport>(ioc, reportIds));
158 break;
159 }
160 }
161 }
162 }
163
164 } // namespace numeric
165
166 namespace discrete
167 {
168
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)169 void LogToJournal::commit(
170 const std::string& triggerId, const ThresholdName thresholdNameIn,
171 const std::string& sensorName, const Milliseconds timestamp,
172 const TriggerValue triggerValue)
173 {
174 auto value = std::get<std::string>(triggerValue);
175
176 std::string msg =
177 "Discrete condition '" + thresholdNameIn->get() + "' of trigger '" +
178 triggerId + "' is met on sensor " + sensorName +
179 ", recorded value: " + value + ", severity: " +
180 std::string(utils::toShortEnum(utils::enumToString(severity))) +
181 ", timestamp: " + timestampToString(timestamp);
182
183 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
184 }
185
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)186 void LogToRedfishEventLog::commit(
187 const std::string& triggerId, const ThresholdName thresholdNameIn,
188 const std::string& sensorName, const Milliseconds timestamp,
189 const TriggerValue triggerValue)
190 {
191 auto value = std::get<std::string>(triggerValue);
192
193 phosphor::logging::log<phosphor::logging::level::INFO>(
194 "Logging discrete trigger action to Redfish Event Log.",
195 phosphor::logging::entry(
196 "REDFISH_MESSAGE_ID=%s",
197 redfish_message_ids::TriggerDiscreteConditionMet),
198 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s",
199 sensorName.c_str(), value.c_str(),
200 triggerId.c_str()));
201 }
202
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)203 void fillActions(
204 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
205 const std::vector<TriggerAction>& ActionsEnum,
206 ::discrete::Severity severity, boost::asio::io_context& ioc,
207 const std::shared_ptr<std::vector<std::string>>& reportIds)
208 {
209 actionsIf.reserve(ActionsEnum.size());
210 for (auto actionType : ActionsEnum)
211 {
212 switch (actionType)
213 {
214 case TriggerAction::LogToJournal:
215 {
216 actionsIf.emplace_back(
217 std::make_unique<LogToJournal>(severity));
218 break;
219 }
220 case TriggerAction::LogToRedfishEventLog:
221 {
222 actionsIf.emplace_back(
223 std::make_unique<LogToRedfishEventLog>());
224 break;
225 }
226 case TriggerAction::UpdateReport:
227 {
228 actionsIf.emplace_back(
229 std::make_unique<UpdateReport>(ioc, reportIds));
230 break;
231 }
232 }
233 }
234 }
235
236 namespace onChange
237 {
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)238 void LogToJournal::commit(
239 const std::string& triggerId, const ThresholdName thresholdNameIn,
240 const std::string& sensorName, const Milliseconds timestamp,
241 const TriggerValue triggerValue)
242 {
243 auto value = triggerValueToString(triggerValue);
244 std::string msg =
245 "Discrete condition 'OnChange' of trigger '" + triggerId +
246 "' is met on sensor: " + sensorName + ", recorded value: " + value +
247 ", timestamp: " + timestampToString(timestamp);
248
249 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
250 }
251
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)252 void LogToRedfishEventLog::commit(
253 const std::string& triggerId, const ThresholdName thresholdNameIn,
254 const std::string& sensorName, const Milliseconds timestamp,
255 const TriggerValue triggerValue)
256 {
257 auto value = triggerValueToString(triggerValue);
258
259 phosphor::logging::log<phosphor::logging::level::INFO>(
260 "Logging onChange discrete trigger action to Redfish Event Log.",
261 phosphor::logging::entry(
262 "REDFISH_MESSAGE_ID=%s",
263 redfish_message_ids::TriggerDiscreteConditionMet),
264 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s",
265 sensorName.c_str(), value.c_str(),
266 triggerId.c_str()));
267 }
268
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)269 void fillActions(
270 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf,
271 const std::vector<TriggerAction>& ActionsEnum, boost::asio::io_context& ioc,
272 const std::shared_ptr<std::vector<std::string>>& reportIds)
273 {
274 actionsIf.reserve(ActionsEnum.size());
275 for (auto actionType : ActionsEnum)
276 {
277 switch (actionType)
278 {
279 case TriggerAction::LogToJournal:
280 {
281 actionsIf.emplace_back(std::make_unique<LogToJournal>());
282 break;
283 }
284 case TriggerAction::LogToRedfishEventLog:
285 {
286 actionsIf.emplace_back(
287 std::make_unique<LogToRedfishEventLog>());
288 break;
289 }
290 case TriggerAction::UpdateReport:
291 {
292 actionsIf.emplace_back(
293 std::make_unique<UpdateReport>(ioc, reportIds));
294 break;
295 }
296 }
297 }
298 }
299 } // namespace onChange
300 } // namespace discrete
301
commit(const std::string & triggerId,const ThresholdName thresholdNameIn,const std::string & sensorName,const Milliseconds timestamp,const TriggerValue triggerValue)302 void UpdateReport::commit(
303 const std::string& triggerId, const ThresholdName thresholdNameIn,
304 const std::string& sensorName, const Milliseconds timestamp,
305 const TriggerValue triggerValue)
306 {
307 if (reportIds->empty())
308 {
309 return;
310 }
311
312 utils::Messanger messanger(ioc);
313 messanger.send(messages::UpdateReportInd{*reportIds});
314 }
315 } // namespace action
316