Add match threshold alarm signals for threshold events
Add SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS option to enable
monitoring the alarm signals on sensor threshold interfaces:
https://gerrit.openbmc-project.xyz/39899
Tested:
Change the threshold to trigger the alarm signal:
busctl set-property xyz.openbmc_project.Hwmon-487368426.Hwmon1
/xyz/openbmc_project/sensors/temperature/cputemp
xyz.openbmc_project.Sensor.Threshold.Critical CriticalHigh d 30
trigger the event log:
1 | Pre-Init |0000000213| Temperature cputemp
| Upper Critical going high | Asserted
| Reading 35 > Threshold 30 degrees C
Note:
It needs to work with the following PR:
https://gerrit.openbmc-project.xyz/42212
Signed-off-by: George Hung <george.hung@quantatw.com>
Change-Id: I86a7061895ba082643d1f9e0222b52b1bd732083
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 779093b..86a85a3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,12 +32,20 @@
OFF
)
+option (
+ SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
+ "Enable SEL Logger to monitor threshold alarm signals and
+ automatically log SEL records for threshold sensor events"
+ OFF
+)
+
target_compile_definitions (
sel-logger PRIVATE
$<$<BOOL:${SEL_LOGGER_MONITOR_THRESHOLD_EVENTS}>: -DSEL_LOGGER_MONITOR_THRESHOLD_EVENTS>
$<$<BOOL:${REDFISH_LOG_MONITOR_PULSE_EVENTS}>: -DREDFISH_LOG_MONITOR_PULSE_EVENTS>
$<$<BOOL:${SEL_LOGGER_MONITOR_WATCHDOG_EVENTS}>: -DSEL_LOGGER_MONITOR_WATCHDOG_EVENTS>
$<$<BOOL:${SEL_LOGGER_SEND_TO_LOGGING_SERVICE}>: -DSEL_LOGGER_SEND_TO_LOGGING_SERVICE>
+ $<$<BOOL:${SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS}>: -DSEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS>
)
target_include_directories (sel-logger PRIVATE ${CMAKE_SOURCE_DIR})
diff --git a/include/threshold_alarm_event_monitor.hpp b/include/threshold_alarm_event_monitor.hpp
new file mode 100644
index 0000000..9b942f2
--- /dev/null
+++ b/include/threshold_alarm_event_monitor.hpp
@@ -0,0 +1,261 @@
+/*
+// Copyright (c) 2021 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#pragma once
+#include <boost/container/flat_map.hpp>
+#include <sel_logger.hpp>
+#include <sensorutils.hpp>
+
+#include <map>
+#include <string_view>
+#include <variant>
+
+using sdbusMatch = std::shared_ptr<sdbusplus::bus::match::match>;
+static sdbusMatch warningLowAssertedMatcher;
+static sdbusMatch warningLowDeassertedMatcher;
+static sdbusMatch warningHighAssertedMatcher;
+static sdbusMatch warningHighDeassertedMatcher;
+static sdbusMatch criticalLowAssertedMatcher;
+static sdbusMatch criticalLowDeassertedMatcher;
+static sdbusMatch criticalHighAssertedMatcher;
+static sdbusMatch criticalHighDeassertedMatcher;
+
+static boost::container::flat_map<std::string, sdbusMatch> matchers = {
+ {"WarningLowAlarmAsserted", warningLowAssertedMatcher},
+ {"WarningLowAlarmDeasserted", warningLowDeassertedMatcher},
+ {"WarningHighAlarmAsserted", warningHighAssertedMatcher},
+ {"WarningHighAlarmDeasserted", warningHighDeassertedMatcher},
+ {"CriticalLowAlarmAsserted", criticalLowAssertedMatcher},
+ {"CriticalLowAlarmDeasserted", criticalLowDeassertedMatcher},
+ {"CriticalHighAlarmAsserted", criticalHighAssertedMatcher},
+ {"CriticalHighAlarmDeasserted", criticalHighDeassertedMatcher}};
+
+void generateEvent(std::string signalName,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ sdbusplus::message::message& msg)
+{
+ double assertValue;
+ try
+ {
+ msg.read(assertValue);
+ }
+ catch (sdbusplus::exception_t&)
+ {
+ std::cerr << "error getting assert signal data from " << msg.get_path()
+ << "\n";
+ return;
+ }
+
+ std::string event;
+ std::string thresholdInterface;
+ std::string threshold;
+ std::string direction;
+ bool assert = false;
+ std::vector<uint8_t> eventData(selEvtDataMaxSize, selEvtDataUnspecified);
+ std::string redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion;
+
+ if (signalName == "WarningLowAlarmAsserted" ||
+ signalName == "WarningLowAlarmDeasserted")
+ {
+ event = "WarningLow";
+ thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Warning";
+ eventData[0] =
+ static_cast<uint8_t>(thresholdEventOffsets::lowerNonCritGoingLow);
+ threshold = "warning low";
+ if (signalName == "WarningLowAlarmAsserted")
+ {
+ assert = true;
+ direction = "low";
+ redfishMessageID += ".SensorThresholdWarningLowGoingLow";
+ }
+ else if (signalName == "WarningLowAlarmDeasserted")
+ {
+ direction = "high";
+ redfishMessageID += ".SensorThresholdWarningLowGoingHigh";
+ }
+ }
+ else if (signalName == "WarningHighAlarmAsserted" ||
+ signalName == "WarningHighAlarmDeasserted")
+ {
+ event = "WarningHigh";
+ thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Warning";
+ eventData[0] =
+ static_cast<uint8_t>(thresholdEventOffsets::upperNonCritGoingHigh);
+ threshold = "warning high";
+ if (signalName == "WarningHighAlarmAsserted")
+ {
+ assert = true;
+ direction = "high";
+ redfishMessageID += ".SensorThresholdWarningHighGoingHigh";
+ }
+ else if (signalName == "WarningHighAlarmDeasserted")
+ {
+ direction = "low";
+ redfishMessageID += ".SensorThresholdWarningHighGoingLow";
+ }
+ }
+ else if (signalName == "CriticalLowAlarmAsserted" ||
+ signalName == "CriticalLowAlarmDeasserted")
+ {
+ event = "CriticalLow";
+ thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Critical";
+ eventData[0] =
+ static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
+ threshold = "critical low";
+ if (signalName == "CriticalLowAlarmAsserted")
+ {
+ assert = true;
+ direction = "low";
+ redfishMessageID += ".SensorThresholdCriticalLowGoingLow";
+ }
+ else if (signalName == "CriticalLowAlarmDeasserted")
+ {
+ direction = "high";
+ redfishMessageID += ".SensorThresholdCriticalLowGoingHigh";
+ }
+ }
+ else if (signalName == "CriticalHighAlarmAsserted" ||
+ signalName == "CriticalHighAlarmDeasserted")
+ {
+ event = "CriticalHigh";
+ thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Critical";
+ eventData[0] =
+ static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
+ threshold = "critical high";
+ if (signalName == "CriticalHighAlarmAsserted")
+ {
+ assert = true;
+ direction = "high";
+ redfishMessageID += ".SensorThresholdCriticalHighGoingHigh";
+ }
+ else if (signalName == "CriticalHighAlarmDeasserted")
+ {
+ direction = "low";
+ redfishMessageID += ".SensorThresholdCriticalHighGoingLow";
+ }
+ }
+ // Indicate that bytes 2 and 3 are threshold sensor trigger values
+ eventData[0] |= thresholdEventDataTriggerReadingByte2 |
+ thresholdEventDataTriggerReadingByte3;
+
+ // Get the sensor reading to put in the event data
+ sdbusplus::message::message getSensorValue =
+ conn->new_method_call(msg.get_sender(), msg.get_path(),
+ "org.freedesktop.DBus.Properties", "GetAll");
+ getSensorValue.append("xyz.openbmc_project.Sensor.Value");
+ boost::container::flat_map<std::string, std::variant<double, int64_t>>
+ sensorValue;
+ try
+ {
+ sdbusplus::message::message getSensorValueResp =
+ conn->call(getSensorValue);
+ getSensorValueResp.read(sensorValue);
+ }
+ catch (sdbusplus::exception_t&)
+ {
+ std::cerr << "error getting sensor value from " << msg.get_path()
+ << "\n";
+ return;
+ }
+ double max = 0;
+ auto findMax = sensorValue.find("MaxValue");
+ if (findMax != sensorValue.end())
+ {
+ max = std::visit(ipmi::VariantToDoubleVisitor(), findMax->second);
+ }
+ double min = 0;
+ auto findMin = sensorValue.find("MinValue");
+ if (findMin != sensorValue.end())
+ {
+ min = std::visit(ipmi::VariantToDoubleVisitor(), findMin->second);
+ }
+
+ try
+ {
+ eventData[1] = ipmi::getScaledIPMIValue(assertValue, max, min);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what();
+ eventData[1] = selEvtDataUnspecified;
+ }
+
+ // Get the threshold value to put in the event data
+ sdbusplus::message::message getThreshold =
+ conn->new_method_call(msg.get_sender(), msg.get_path(),
+ "org.freedesktop.DBus.Properties", "Get");
+ getThreshold.append(thresholdInterface, event);
+ std::variant<double, int64_t> thresholdValue;
+ try
+ {
+ sdbusplus::message::message getThresholdResp = conn->call(getThreshold);
+ getThresholdResp.read(thresholdValue);
+ }
+ catch (sdbusplus::exception_t&)
+ {
+ std::cerr << "error getting sensor threshold from " << msg.get_path()
+ << "\n";
+ return;
+ }
+ double thresholdVal =
+ std::visit(ipmi::VariantToDoubleVisitor(), thresholdValue);
+
+ double scale = 0;
+ auto findScale = sensorValue.find("Scale");
+ if (findScale != sensorValue.end())
+ {
+ scale = std::visit(ipmi::VariantToDoubleVisitor(), findScale->second);
+ thresholdVal *= std::pow(10, scale);
+ }
+ try
+ {
+ eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what();
+ eventData[2] = selEvtDataUnspecified;
+ }
+
+ std::string_view sensorName(msg.get_path());
+ sensorName.remove_prefix(
+ std::min(sensorName.find_last_of("/") + 1, sensorName.size()));
+
+ std::string journalMsg(std::string(sensorName) + " sensor crossed a " +
+ threshold + " threshold going " + direction +
+ ". Reading=" + std::to_string(assertValue) +
+ " Threshold=" + std::to_string(thresholdVal) + ".");
+
+ selAddSystemRecord(journalMsg, std::string(msg.get_path()), eventData,
+ assert, selBMCGenID, "REDFISH_MESSAGE_ID=%s",
+ redfishMessageID.c_str(),
+ "REDFISH_MESSAGE_ARGS=%.*s,%f,%f", sensorName.length(),
+ sensorName.data(), assertValue, thresholdVal);
+}
+
+inline static void startThresholdAlarmMonitor(
+ std::shared_ptr<sdbusplus::asio::connection> conn)
+{
+ for (auto iter = matchers.begin(); iter != matchers.end(); iter++)
+ {
+ iter->second = std::make_shared<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus&>(*conn),
+ "type='signal',member=" + iter->first,
+ [conn, iter](sdbusplus::message::message& msg) {
+ generateEvent(iter->first, conn, msg);
+ });
+ }
+}
diff --git a/src/sel_logger.cpp b/src/sel_logger.cpp
index 99527b1..83d487a 100644
--- a/src/sel_logger.cpp
+++ b/src/sel_logger.cpp
@@ -24,6 +24,9 @@
#include <sel_logger.hpp>
#include <threshold_event_monitor.hpp>
#include <watchdog_event_monitor.hpp>
+#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
+#include <threshold_alarm_event_monitor.hpp>
+#endif
#include <filesystem>
#include <fstream>
@@ -248,6 +251,10 @@
sdbusplus::bus::match::match watchdogEventMonitor =
startWatchdogEventMonitor(conn);
#endif
+
+#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
+ startThresholdAlarmMonitor(conn);
+#endif
io.run();
return 0;