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