1 #include "trigger_actions.hpp" 2 3 #include "messages/update_report_ind.hpp" 4 #include "types/trigger_types.hpp" 5 #include "utils/messanger.hpp" 6 7 #include <phosphor-logging/log.hpp> 8 9 #include <ctime> 10 11 namespace action 12 { 13 14 namespace 15 { 16 std::string timestampToString(Milliseconds timestamp) 17 { 18 std::time_t t = static_cast<time_t>(timestamp.count()); 19 std::array<char, sizeof("YYYY-MM-DDThh:mm:ssZ")> buf = {}; 20 size_t size = 21 std::strftime(buf.data(), buf.size(), "%FT%TZ", std::gmtime(&t)); 22 if (size == 0) 23 { 24 throw std::runtime_error("Failed to parse timestamp to string"); 25 } 26 return std::string(buf.data(), size); 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& sensorName, Milliseconds timestamp, 47 double value) 48 { 49 std::string msg = ::numeric::typeToString(type) + 50 " numeric threshold condition is met on sensor " + 51 sensorName + ", recorded value " + std::to_string(value) + 52 ", timestamp " + timestampToString(timestamp) + 53 ", direction " + 54 std::string(getDirection(value, threshold)); 55 56 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str()); 57 } 58 59 const char* LogToRedfish::getMessageId() const 60 { 61 switch (type) 62 { 63 case ::numeric::Type::upperCritical: 64 return "OpenBMC.0.1.0.NumericThresholdUpperCritical"; 65 case ::numeric::Type::lowerCritical: 66 return "OpenBMC.0.1.0.NumericThresholdLowerCritical"; 67 case ::numeric::Type::upperWarning: 68 return "OpenBMC.0.1.0.NumericThresholdUpperWarning"; 69 case ::numeric::Type::lowerWarning: 70 return "OpenBMC.0.1.0.NumericThresholdLowerWarning"; 71 } 72 throw std::runtime_error("Invalid type"); 73 } 74 75 void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp, 76 double value) 77 { 78 phosphor::logging::log<phosphor::logging::level::INFO>( 79 "Threshold value is exceeded", 80 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()), 81 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu,%s", 82 sensorName.c_str(), value, timestamp.count(), 83 getDirection(value, threshold))); 84 } 85 86 void fillActions( 87 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf, 88 const std::vector<TriggerAction>& ActionsEnum, ::numeric::Type type, 89 double thresholdValue, boost::asio::io_context& ioc, 90 const std::shared_ptr<std::vector<std::string>>& reportIds) 91 { 92 actionsIf.reserve(ActionsEnum.size()); 93 for (auto actionType : ActionsEnum) 94 { 95 switch (actionType) 96 { 97 case TriggerAction::LogToLogService: 98 { 99 actionsIf.emplace_back( 100 std::make_unique<LogToJournal>(type, thresholdValue)); 101 break; 102 } 103 case TriggerAction::RedfishEvent: 104 { 105 actionsIf.emplace_back( 106 std::make_unique<LogToRedfish>(type, thresholdValue)); 107 break; 108 } 109 case TriggerAction::UpdateReport: 110 { 111 actionsIf.emplace_back( 112 std::make_unique<UpdateReport>(ioc, reportIds)); 113 break; 114 } 115 } 116 } 117 } 118 119 } // namespace numeric 120 121 namespace discrete 122 { 123 void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp, 124 double value) 125 { 126 std::string msg = ::discrete::severityToString(severity) + 127 " discrete threshold condition is met on sensor " + 128 sensorName + ", recorded value " + std::to_string(value) + 129 ", timestamp " + timestampToString(timestamp); 130 131 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str()); 132 } 133 134 const char* LogToRedfish::getMessageId() const 135 { 136 switch (severity) 137 { 138 case ::discrete::Severity::ok: 139 return "OpenBMC.0.1.0.DiscreteThresholdOk"; 140 case ::discrete::Severity::warning: 141 return "OpenBMC.0.1.0.DiscreteThresholdWarning"; 142 case ::discrete::Severity::critical: 143 return "OpenBMC.0.1.0.DiscreteThresholdCritical"; 144 } 145 throw std::runtime_error("Invalid severity"); 146 } 147 148 void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp, 149 double value) 150 { 151 phosphor::logging::log<phosphor::logging::level::INFO>( 152 "Discrete treshold condition is met", 153 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()), 154 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu", 155 sensorName.c_str(), value, timestamp.count())); 156 } 157 158 void fillActions( 159 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf, 160 const std::vector<TriggerAction>& ActionsEnum, 161 ::discrete::Severity severity, boost::asio::io_context& ioc, 162 const std::shared_ptr<std::vector<std::string>>& reportIds) 163 { 164 actionsIf.reserve(ActionsEnum.size()); 165 for (auto actionType : ActionsEnum) 166 { 167 switch (actionType) 168 { 169 case TriggerAction::LogToLogService: 170 { 171 actionsIf.emplace_back( 172 std::make_unique<LogToJournal>(severity)); 173 break; 174 } 175 case TriggerAction::RedfishEvent: 176 { 177 actionsIf.emplace_back( 178 std::make_unique<LogToRedfish>(severity)); 179 break; 180 } 181 case TriggerAction::UpdateReport: 182 { 183 actionsIf.emplace_back( 184 std::make_unique<UpdateReport>(ioc, reportIds)); 185 break; 186 } 187 } 188 } 189 } 190 191 namespace onChange 192 { 193 void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp, 194 double value) 195 { 196 std::string msg = "Value changed on sensor " + sensorName + 197 ", recorded value " + std::to_string(value) + 198 ", timestamp " + timestampToString(timestamp); 199 200 phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str()); 201 } 202 203 void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp, 204 double value) 205 { 206 const char* messageId = "OpenBMC.0.1.0.DiscreteThresholdOnChange"; 207 phosphor::logging::log<phosphor::logging::level::INFO>( 208 "Uncondtional discrete threshold triggered", 209 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId), 210 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu", 211 sensorName.c_str(), value, timestamp.count())); 212 } 213 214 void fillActions( 215 std::vector<std::unique_ptr<interfaces::TriggerAction>>& actionsIf, 216 const std::vector<TriggerAction>& ActionsEnum, boost::asio::io_context& ioc, 217 const std::shared_ptr<std::vector<std::string>>& reportIds) 218 { 219 actionsIf.reserve(ActionsEnum.size()); 220 for (auto actionType : ActionsEnum) 221 { 222 switch (actionType) 223 { 224 case TriggerAction::LogToLogService: 225 { 226 actionsIf.emplace_back(std::make_unique<LogToJournal>()); 227 break; 228 } 229 case TriggerAction::RedfishEvent: 230 { 231 actionsIf.emplace_back(std::make_unique<LogToRedfish>()); 232 break; 233 } 234 case TriggerAction::UpdateReport: 235 { 236 actionsIf.emplace_back( 237 std::make_unique<UpdateReport>(ioc, reportIds)); 238 break; 239 } 240 } 241 } 242 } 243 } // namespace onChange 244 } // namespace discrete 245 246 void UpdateReport::commit(const std::string&, Milliseconds, double) 247 { 248 if (reportIds->empty()) 249 { 250 return; 251 } 252 253 utils::Messanger messanger(ioc); 254 messanger.send(messages::UpdateReportInd{*reportIds}); 255 } 256 } // namespace action 257