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