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 { 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 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 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 67 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 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 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 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 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 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 { 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 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 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 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