| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 1 | /** | 
 | 2 |  * Copyright © 2021 IBM Corporation | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 | #include "threshold_alarm_logger.hpp" | 
 | 17 |  | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 18 | #include "sdbusplus.hpp" | 
 | 19 |  | 
| Matt Spinler | 3efec61 | 2021-05-11 15:26:17 -0500 | [diff] [blame] | 20 | #include <unistd.h> | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 21 |  | 
 | 22 | #include <phosphor-logging/log.hpp> | 
 | 23 | #include <xyz/openbmc_project/Logging/Entry/server.hpp> | 
 | 24 |  | 
| Patrick Williams | fbf4703 | 2023-07-17 12:27:34 -0500 | [diff] [blame] | 25 | #include <format> | 
 | 26 |  | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 27 | namespace sensor::monitor | 
 | 28 | { | 
 | 29 |  | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 30 | using namespace sdbusplus::xyz::openbmc_project::Logging::server; | 
 | 31 | using namespace phosphor::logging; | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 32 | using namespace phosphor::fan; | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 33 | using namespace phosphor::fan::util; | 
 | 34 |  | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 35 | const std::string warningInterface = | 
 | 36 |     "xyz.openbmc_project.Sensor.Threshold.Warning"; | 
 | 37 | const std::string criticalInterface = | 
 | 38 |     "xyz.openbmc_project.Sensor.Threshold.Critical"; | 
 | 39 | const std::string perfLossInterface = | 
 | 40 |     "xyz.openbmc_project.Sensor.Threshold.PerformanceLoss"; | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 41 | constexpr auto loggingService = "xyz.openbmc_project.Logging"; | 
 | 42 | constexpr auto loggingPath = "/xyz/openbmc_project/logging"; | 
 | 43 | constexpr auto loggingCreateIface = "xyz.openbmc_project.Logging.Create"; | 
 | 44 | constexpr auto errorNameBase = "xyz.openbmc_project.Sensor.Threshold.Error."; | 
 | 45 | constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value"; | 
 | 46 | constexpr auto assocInterface = "xyz.openbmc_project.Association"; | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 47 |  | 
| Matt Spinler | 8ce6507 | 2022-11-03 15:15:55 -0400 | [diff] [blame] | 48 | const std::vector<std::string> thresholdIfaceNames{ | 
 | 49 |     warningInterface, criticalInterface, perfLossInterface}; | 
 | 50 |  | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 51 | using ErrorData = std::tuple<ErrorName, ErrorStatus, Entry::Level>; | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 52 |  | 
 | 53 | /** | 
 | 54 |  * Map of threshold interfaces and alarm properties and values to error data. | 
 | 55 |  */ | 
 | 56 | const std::map<InterfaceName, std::map<PropertyName, std::map<bool, ErrorData>>> | 
 | 57 |     thresholdData{ | 
 | 58 |  | 
 | 59 |         {warningInterface, | 
 | 60 |          {{"WarningAlarmHigh", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 61 |            {{true, ErrorData{"WarningHigh", "", Entry::Level::Warning}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 62 |             {false, | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 63 |              ErrorData{"WarningHigh", "Clear", Entry::Level::Informational}}}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 64 |           {"WarningAlarmLow", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 65 |            {{true, ErrorData{"WarningLow", "", Entry::Level::Warning}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 66 |             {false, | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 67 |              ErrorData{"WarningLow", "Clear", Entry::Level::Informational}}}}}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 68 |  | 
 | 69 |         {criticalInterface, | 
 | 70 |          {{"CriticalAlarmHigh", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 71 |            {{true, ErrorData{"CriticalHigh", "", Entry::Level::Critical}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 72 |             {false, | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 73 |              ErrorData{"CriticalHigh", "Clear", Entry::Level::Informational}}}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 74 |           {"CriticalAlarmLow", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 75 |            {{true, ErrorData{"CriticalLow", "", Entry::Level::Critical}}, | 
 | 76 |             {false, ErrorData{"CriticalLow", "Clear", | 
 | 77 |                               Entry::Level::Informational}}}}}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 78 |  | 
 | 79 |         {perfLossInterface, | 
 | 80 |          {{"PerfLossAlarmHigh", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 81 |            {{true, ErrorData{"PerformanceLossHigh", "", Entry::Level::Warning}}, | 
 | 82 |             {false, ErrorData{"PerformanceLossHigh", "Clear", | 
 | 83 |                               Entry::Level::Informational}}}}, | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 84 |           {"PerfLossAlarmLow", | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 85 |            {{true, ErrorData{"PerformanceLossLow", "", Entry::Level::Warning}}, | 
 | 86 |             {false, ErrorData{"PerformanceLossLow", "Clear", | 
 | 87 |                               Entry::Level::Informational}}}}}}}; | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 88 |  | 
| Matt Spinler | 7f6946b | 2021-05-14 12:43:50 -0500 | [diff] [blame] | 89 | ThresholdAlarmLogger::ThresholdAlarmLogger( | 
| Patrick Williams | cb356d4 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 90 |     sdbusplus::bus_t& bus, sdeventplus::Event& event, | 
| Matt Spinler | 7f6946b | 2021-05-14 12:43:50 -0500 | [diff] [blame] | 91 |     std::shared_ptr<PowerState> powerState) : | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 92 |     bus(bus), | 
| Matt Spinler | 7f6946b | 2021-05-14 12:43:50 -0500 | [diff] [blame] | 93 |     event(event), _powerState(std::move(powerState)), | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 94 |     warningMatch(bus, | 
 | 95 |                  "type='signal',member='PropertiesChanged'," | 
 | 96 |                  "path_namespace='/xyz/openbmc_project/sensors'," | 
 | 97 |                  "arg0='" + | 
 | 98 |                      warningInterface + "'", | 
 | 99 |                  std::bind(&ThresholdAlarmLogger::propertiesChanged, this, | 
 | 100 |                            std::placeholders::_1)), | 
 | 101 |     criticalMatch(bus, | 
 | 102 |                   "type='signal',member='PropertiesChanged'," | 
 | 103 |                   "path_namespace='/xyz/openbmc_project/sensors'," | 
 | 104 |                   "arg0='" + | 
 | 105 |                       criticalInterface + "'", | 
 | 106 |                   std::bind(&ThresholdAlarmLogger::propertiesChanged, this, | 
 | 107 |                             std::placeholders::_1)), | 
 | 108 |     perfLossMatch(bus, | 
 | 109 |                   "type='signal',member='PropertiesChanged'," | 
 | 110 |                   "path_namespace='/xyz/openbmc_project/sensors'," | 
 | 111 |                   "arg0='" + | 
 | 112 |                       perfLossInterface + "'", | 
 | 113 |                   std::bind(&ThresholdAlarmLogger::propertiesChanged, this, | 
| Matt Spinler | b7a5540 | 2021-10-11 13:45:35 -0500 | [diff] [blame] | 114 |                             std::placeholders::_1)), | 
 | 115 |     ifacesRemovedMatch(bus, | 
 | 116 |                        "type='signal',member='InterfacesRemoved',arg0path=" | 
 | 117 |                        "'/xyz/openbmc_project/sensors/'", | 
 | 118 |                        std::bind(&ThresholdAlarmLogger::interfacesRemoved, this, | 
| Matt Spinler | 8ce6507 | 2022-11-03 15:15:55 -0400 | [diff] [blame] | 119 |                                  std::placeholders::_1)), | 
 | 120 |     ifacesAddedMatch(bus, | 
 | 121 |                      "type='signal',member='InterfacesAdded',arg0path=" | 
 | 122 |                      "'/xyz/openbmc_project/sensors/'", | 
 | 123 |                      std::bind(&ThresholdAlarmLogger::interfacesAdded, this, | 
 | 124 |                                std::placeholders::_1)) | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 125 | { | 
| Matt Spinler | 7f6946b | 2021-05-14 12:43:50 -0500 | [diff] [blame] | 126 |     _powerState->addCallback("thresholdMon", | 
 | 127 |                              std::bind(&ThresholdAlarmLogger::powerStateChanged, | 
 | 128 |                                        this, std::placeholders::_1)); | 
 | 129 |  | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 130 |     // check for any currently asserted threshold alarms | 
| Patrick Williams | 61b7329 | 2023-05-10 07:50:12 -0500 | [diff] [blame] | 131 |     std::for_each(thresholdData.begin(), thresholdData.end(), | 
 | 132 |                   [this](const auto& thresholdInterface) { | 
 | 133 |         const auto& interface = thresholdInterface.first; | 
 | 134 |         auto objects = SDBusPlus::getSubTreeRaw(this->bus, "/", interface, 0); | 
 | 135 |         std::for_each(objects.begin(), objects.end(), | 
 | 136 |                       [interface, this](const auto& object) { | 
 | 137 |             const auto& path = object.first; | 
 | 138 |             const auto& service = object.second.begin()->first; | 
 | 139 |             checkThresholds(interface, path, service); | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 140 |         }); | 
| Patrick Williams | 61b7329 | 2023-05-10 07:50:12 -0500 | [diff] [blame] | 141 |     }); | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 142 | } | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 143 |  | 
| Patrick Williams | cb356d4 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 144 | void ThresholdAlarmLogger::propertiesChanged(sdbusplus::message_t& msg) | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 145 | { | 
| Matt Spinler | f5d3be4 | 2021-02-01 16:38:01 -0600 | [diff] [blame] | 146 |     std::map<std::string, std::variant<bool>> properties; | 
 | 147 |     std::string sensorPath = msg.get_path(); | 
 | 148 |     std::string interface; | 
 | 149 |  | 
 | 150 |     msg.read(interface, properties); | 
 | 151 |  | 
| Matt Spinler | 8ce6507 | 2022-11-03 15:15:55 -0400 | [diff] [blame] | 152 |     checkProperties(sensorPath, interface, properties); | 
 | 153 | } | 
 | 154 |  | 
 | 155 | void ThresholdAlarmLogger::interfacesRemoved(sdbusplus::message_t& msg) | 
 | 156 | { | 
 | 157 |     sdbusplus::message::object_path path; | 
 | 158 |     std::vector<std::string> interfaces; | 
 | 159 |  | 
 | 160 |     msg.read(path, interfaces); | 
 | 161 |  | 
 | 162 |     for (const auto& interface : interfaces) | 
 | 163 |     { | 
 | 164 |         if (std::find(thresholdIfaceNames.begin(), thresholdIfaceNames.end(), | 
 | 165 |                       interface) != thresholdIfaceNames.end()) | 
 | 166 |         { | 
 | 167 |             alarms.erase(InterfaceKey{path, interface}); | 
 | 168 |         } | 
 | 169 |     } | 
 | 170 | } | 
 | 171 |  | 
 | 172 | void ThresholdAlarmLogger::interfacesAdded(sdbusplus::message_t& msg) | 
 | 173 | { | 
 | 174 |     sdbusplus::message::object_path path; | 
 | 175 |     std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces; | 
 | 176 |  | 
 | 177 |     msg.read(path, interfaces); | 
 | 178 |  | 
 | 179 |     for (const auto& [interface, properties] : interfaces) | 
 | 180 |     { | 
 | 181 |         if (std::find(thresholdIfaceNames.begin(), thresholdIfaceNames.end(), | 
 | 182 |                       interface) != thresholdIfaceNames.end()) | 
 | 183 |         { | 
 | 184 |             checkProperties(path, interface, properties); | 
 | 185 |         } | 
 | 186 |     } | 
 | 187 | } | 
 | 188 |  | 
 | 189 | void ThresholdAlarmLogger::checkProperties( | 
 | 190 |     const std::string& sensorPath, const std::string& interface, | 
 | 191 |     const std::map<std::string, std::variant<bool>>& properties) | 
 | 192 | { | 
| Matt Spinler | f5d3be4 | 2021-02-01 16:38:01 -0600 | [diff] [blame] | 193 |     auto alarmProperties = thresholdData.find(interface); | 
 | 194 |     if (alarmProperties == thresholdData.end()) | 
 | 195 |     { | 
 | 196 |         return; | 
 | 197 |     } | 
 | 198 |  | 
 | 199 |     for (const auto& [propertyName, propertyValue] : properties) | 
 | 200 |     { | 
 | 201 |         if (alarmProperties->second.find(propertyName) != | 
 | 202 |             alarmProperties->second.end()) | 
 | 203 |         { | 
 | 204 |             // If this is the first time we've seen this alarm, then | 
 | 205 |             // assume it was off before so it doesn't create an event | 
 | 206 |             // log for a value of false. | 
 | 207 |  | 
 | 208 |             InterfaceKey key{sensorPath, interface}; | 
 | 209 |             if (alarms.find(key) == alarms.end()) | 
 | 210 |             { | 
 | 211 |                 alarms[key][propertyName] = false; | 
 | 212 |             } | 
 | 213 |  | 
 | 214 |             // Check if the value changed from what was there before. | 
 | 215 |             auto alarmValue = std::get<bool>(propertyValue); | 
 | 216 |             if (alarmValue != alarms[key][propertyName]) | 
 | 217 |             { | 
 | 218 |                 alarms[key][propertyName] = alarmValue; | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 219 |  | 
 | 220 |                 if (_powerState->isPowerOn()) | 
 | 221 |                 { | 
 | 222 |                     createEventLog(sensorPath, interface, propertyName, | 
 | 223 |                                    alarmValue); | 
 | 224 |                 } | 
| Matt Spinler | f5d3be4 | 2021-02-01 16:38:01 -0600 | [diff] [blame] | 225 |             } | 
 | 226 |         } | 
 | 227 |     } | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 228 | } | 
 | 229 |  | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 230 | void ThresholdAlarmLogger::checkThresholds(const std::string& interface, | 
 | 231 |                                            const std::string& sensorPath, | 
 | 232 |                                            const std::string& service) | 
 | 233 | { | 
 | 234 |     auto properties = thresholdData.find(interface); | 
 | 235 |     if (properties == thresholdData.end()) | 
 | 236 |     { | 
 | 237 |         return; | 
 | 238 |     } | 
 | 239 |  | 
 | 240 |     for (const auto& [property, unused] : properties->second) | 
 | 241 |     { | 
 | 242 |         try | 
 | 243 |         { | 
 | 244 |             auto alarmValue = SDBusPlus::getProperty<bool>( | 
 | 245 |                 bus, service, sensorPath, interface, property); | 
 | 246 |             alarms[InterfaceKey(sensorPath, interface)][property] = alarmValue; | 
 | 247 |  | 
 | 248 |             // This is just for checking alarms on startup, | 
 | 249 |             // so only look for active alarms. | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 250 |             if (alarmValue && _powerState->isPowerOn()) | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 251 |             { | 
 | 252 |                 createEventLog(sensorPath, interface, property, alarmValue); | 
 | 253 |             } | 
 | 254 |         } | 
| Patrick Williams | cb356d4 | 2022-07-22 19:26:53 -0500 | [diff] [blame] | 255 |         catch (const sdbusplus::exception_t& e) | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 256 |         { | 
| Matt Spinler | 4b51592 | 2021-10-11 14:55:50 -0500 | [diff] [blame] | 257 |             // Sensor daemons that get their direction from entity manager | 
 | 258 |             // may only be putting either the high alarm or low alarm on | 
 | 259 |             // D-Bus, not both. | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 260 |             continue; | 
 | 261 |         } | 
 | 262 |     } | 
 | 263 | } | 
 | 264 |  | 
 | 265 | void ThresholdAlarmLogger::createEventLog(const std::string& sensorPath, | 
 | 266 |                                           const std::string& interface, | 
 | 267 |                                           const std::string& alarmProperty, | 
 | 268 |                                           bool alarmValue) | 
 | 269 | { | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 270 |     std::map<std::string, std::string> ad; | 
 | 271 |  | 
 | 272 |     auto type = getSensorType(sensorPath); | 
 | 273 |     if (skipSensorType(type)) | 
 | 274 |     { | 
 | 275 |         return; | 
 | 276 |     } | 
 | 277 |  | 
 | 278 |     auto it = thresholdData.find(interface); | 
 | 279 |     if (it == thresholdData.end()) | 
 | 280 |     { | 
 | 281 |         return; | 
 | 282 |     } | 
 | 283 |  | 
 | 284 |     auto properties = it->second.find(alarmProperty); | 
 | 285 |     if (properties == it->second.end()) | 
 | 286 |     { | 
 | 287 |         log<level::INFO>( | 
| Patrick Williams | fbf4703 | 2023-07-17 12:27:34 -0500 | [diff] [blame] | 288 |             std::format("Could not find {} in threshold alarms map", | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 289 |                         alarmProperty) | 
 | 290 |                 .c_str()); | 
 | 291 |         return; | 
 | 292 |     } | 
 | 293 |  | 
 | 294 |     ad.emplace("SENSOR_NAME", sensorPath); | 
| Matt Spinler | 3efec61 | 2021-05-11 15:26:17 -0500 | [diff] [blame] | 295 |     ad.emplace("_PID", std::to_string(getpid())); | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 296 |  | 
 | 297 |     try | 
 | 298 |     { | 
 | 299 |         auto sensorValue = SDBusPlus::getProperty<double>( | 
 | 300 |             bus, sensorPath, valueInterface, "Value"); | 
 | 301 |  | 
 | 302 |         ad.emplace("SENSOR_VALUE", std::to_string(sensorValue)); | 
 | 303 |  | 
 | 304 |         log<level::INFO>( | 
| Patrick Williams | fbf4703 | 2023-07-17 12:27:34 -0500 | [diff] [blame] | 305 |             std::format("Threshold Event {} {} = {} (sensor value {})", | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 306 |                         sensorPath, alarmProperty, alarmValue, sensorValue) | 
 | 307 |                 .c_str()); | 
 | 308 |     } | 
 | 309 |     catch (const DBusServiceError& e) | 
 | 310 |     { | 
 | 311 |         // If the sensor was just added, the Value interface for it may | 
 | 312 |         // not be in the mapper yet.  This could only happen if the sensor | 
 | 313 |         // application was started up after this one and the value exceeded the | 
 | 314 |         // threshold immediately. | 
| Patrick Williams | fbf4703 | 2023-07-17 12:27:34 -0500 | [diff] [blame] | 315 |         log<level::INFO>(std::format("Threshold Event {} {} = {}", sensorPath, | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 316 |                                      alarmProperty, alarmValue) | 
 | 317 |                              .c_str()); | 
 | 318 |     } | 
 | 319 |  | 
 | 320 |     auto callout = getCallout(sensorPath); | 
 | 321 |     if (!callout.empty()) | 
 | 322 |     { | 
 | 323 |         ad.emplace("CALLOUT_INVENTORY_PATH", callout); | 
 | 324 |     } | 
 | 325 |  | 
 | 326 |     auto errorData = properties->second.find(alarmValue); | 
 | 327 |  | 
 | 328 |     // Add the base error name and the sensor type (like Temperature) to the | 
 | 329 |     // error name that's in the thresholdData name to get something like | 
 | 330 |     // xyz.openbmc_project.Sensor.Threshold.Error.TemperatureWarningHigh | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 331 |     const auto& [name, status, severity] = errorData->second; | 
 | 332 |  | 
 | 333 |     try | 
 | 334 |     { | 
 | 335 |         auto thresholdValue = SDBusPlus::getProperty<double>(bus, sensorPath, | 
 | 336 |                                                              interface, name); | 
 | 337 |  | 
 | 338 |         ad.emplace("THRESHOLD_VALUE", std::to_string(thresholdValue)); | 
 | 339 |  | 
 | 340 |         log<level::INFO>( | 
 | 341 |             std::format("Threshold Event {} {} = {} (threshold value {})", | 
 | 342 |                         sensorPath, alarmProperty, alarmValue, thresholdValue) | 
 | 343 |                 .c_str()); | 
 | 344 |     } | 
 | 345 |     catch (const DBusServiceError& e) | 
 | 346 |     { | 
 | 347 |         log<level::INFO>(std::format("Threshold Event {} {} = {}", sensorPath, | 
 | 348 |                                      alarmProperty, alarmValue) | 
 | 349 |                              .c_str()); | 
 | 350 |     } | 
 | 351 |  | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 352 |     type.front() = toupper(type.front()); | 
| Delphine CC Chiu | 99914e5 | 2024-05-21 17:38:58 +0800 | [diff] [blame] | 353 |     std::string errorName = errorNameBase + type + name + status; | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 354 |  | 
 | 355 |     SDBusPlus::callMethod(loggingService, loggingPath, loggingCreateIface, | 
 | 356 |                           "Create", errorName, convertForMessage(severity), ad); | 
 | 357 | } | 
 | 358 |  | 
 | 359 | std::string ThresholdAlarmLogger::getSensorType(std::string sensorPath) | 
 | 360 | { | 
 | 361 |     auto pos = sensorPath.find_last_of('/'); | 
 | 362 |     if ((sensorPath.back() == '/') || (pos == std::string::npos)) | 
 | 363 |     { | 
 | 364 |         log<level::ERR>( | 
| Patrick Williams | fbf4703 | 2023-07-17 12:27:34 -0500 | [diff] [blame] | 365 |             std::format("Cannot get sensor type from sensor path {}", | 
| Matt Spinler | 2f18267 | 2021-02-01 16:51:38 -0600 | [diff] [blame] | 366 |                         sensorPath) | 
 | 367 |                 .c_str()); | 
 | 368 |         throw std::runtime_error("Invalid sensor path"); | 
 | 369 |     } | 
 | 370 |  | 
 | 371 |     sensorPath = sensorPath.substr(0, pos); | 
 | 372 |     return sensorPath.substr(sensorPath.find_last_of('/') + 1); | 
 | 373 | } | 
 | 374 |  | 
 | 375 | bool ThresholdAlarmLogger::skipSensorType(const std::string& type) | 
 | 376 | { | 
 | 377 |     return (type == "utilization"); | 
 | 378 | } | 
 | 379 |  | 
 | 380 | std::string ThresholdAlarmLogger::getCallout(const std::string& sensorPath) | 
 | 381 | { | 
 | 382 |     const std::array<std::string, 2> assocTypes{"inventory", "chassis"}; | 
 | 383 |  | 
 | 384 |     // Different implementations handle the association to the FRU | 
 | 385 |     // differently: | 
 | 386 |     //  * phosphor-inventory-manager uses the 'inventory' association | 
 | 387 |     //    to point to the FRU. | 
 | 388 |     //  * dbus-sensors/entity-manager uses the 'chassis' association'. | 
 | 389 |     //  * For virtual sensors, no association. | 
 | 390 |  | 
 | 391 |     for (const auto& assocType : assocTypes) | 
 | 392 |     { | 
 | 393 |         auto assocPath = sensorPath + "/" + assocType; | 
 | 394 |  | 
 | 395 |         try | 
 | 396 |         { | 
 | 397 |             auto endpoints = SDBusPlus::getProperty<std::vector<std::string>>( | 
 | 398 |                 bus, assocPath, assocInterface, "endpoints"); | 
 | 399 |  | 
 | 400 |             if (!endpoints.empty()) | 
 | 401 |             { | 
 | 402 |                 return endpoints[0]; | 
 | 403 |             } | 
 | 404 |         } | 
 | 405 |         catch (const DBusServiceError& e) | 
 | 406 |         { | 
 | 407 |             // The association doesn't exist | 
 | 408 |             continue; | 
 | 409 |         } | 
 | 410 |     } | 
 | 411 |  | 
 | 412 |     return std::string{}; | 
| Matt Spinler | 50bf816 | 2021-02-01 16:24:01 -0600 | [diff] [blame] | 413 | } | 
 | 414 |  | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 415 | void ThresholdAlarmLogger::powerStateChanged(bool powerStateOn) | 
 | 416 | { | 
 | 417 |     if (powerStateOn) | 
 | 418 |     { | 
 | 419 |         checkThresholds(); | 
 | 420 |     } | 
 | 421 | } | 
 | 422 |  | 
 | 423 | void ThresholdAlarmLogger::checkThresholds() | 
 | 424 | { | 
| Matt Spinler | eee2580 | 2022-11-03 15:20:13 -0400 | [diff] [blame] | 425 |     std::vector<InterfaceKey> toErase; | 
 | 426 |  | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 427 |     for (const auto& [interfaceKey, alarmMap] : alarms) | 
 | 428 |     { | 
 | 429 |         for (const auto& [propertyName, alarmValue] : alarmMap) | 
 | 430 |         { | 
 | 431 |             if (alarmValue) | 
 | 432 |             { | 
 | 433 |                 const auto& sensorPath = std::get<0>(interfaceKey); | 
 | 434 |                 const auto& interface = std::get<1>(interfaceKey); | 
| Matt Spinler | eee2580 | 2022-11-03 15:20:13 -0400 | [diff] [blame] | 435 |                 std::string service; | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 436 |  | 
| Matt Spinler | eee2580 | 2022-11-03 15:20:13 -0400 | [diff] [blame] | 437 |                 try | 
 | 438 |                 { | 
 | 439 |                     // Check that the service that provides the alarm is still | 
 | 440 |                     // running, because if it died when the alarm was active | 
 | 441 |                     // there would be no indication of it unless we listened | 
 | 442 |                     // for NameOwnerChanged and tracked services, and this is | 
 | 443 |                     // easier. | 
 | 444 |                     service = SDBusPlus::getService(bus, sensorPath, interface); | 
 | 445 |                 } | 
 | 446 |                 catch (const DBusServiceError& e) | 
 | 447 |                 { | 
 | 448 |                     // No longer on D-Bus delete the alarm entry | 
 | 449 |                     toErase.emplace_back(sensorPath, interface); | 
 | 450 |                 } | 
 | 451 |  | 
 | 452 |                 if (!service.empty()) | 
 | 453 |                 { | 
 | 454 |                     createEventLog(sensorPath, interface, propertyName, | 
 | 455 |                                    alarmValue); | 
 | 456 |                 } | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 457 |             } | 
 | 458 |         } | 
 | 459 |     } | 
| Matt Spinler | eee2580 | 2022-11-03 15:20:13 -0400 | [diff] [blame] | 460 |  | 
 | 461 |     for (const auto& e : toErase) | 
 | 462 |     { | 
 | 463 |         alarms.erase(e); | 
 | 464 |     } | 
| Matt Spinler | 66e75a7 | 2021-05-14 10:32:47 -0500 | [diff] [blame] | 465 | } | 
 | 466 |  | 
| Matt Spinler | 403d1f5 | 2021-02-01 15:35:25 -0600 | [diff] [blame] | 467 | } // namespace sensor::monitor |