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