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