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