sysd_monitor: Monitor and log errors
Note some aspects of the code are non-optimal to allow better unit
testing.
Tested:
- Verified failure detected and correct error created in qemu
Change-Id: I1d4c9638fc13147508168278cc5ab90c37e1fb8e
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/systemd_target_signal.cpp b/systemd_target_signal.cpp
new file mode 100644
index 0000000..009a9d0
--- /dev/null
+++ b/systemd_target_signal.cpp
@@ -0,0 +1,111 @@
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdbusplus/server/manager.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdbusplus/exception.hpp>
+#include <systemd_target_signal.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+using phosphor::logging::elog;
+using phosphor::logging::entry;
+using phosphor::logging::level;
+using phosphor::logging::log;
+using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+void SystemdTargetLogging::logError(const std::string& error,
+ const std::string& result)
+{
+ auto method = this->bus.new_method_call(
+ "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
+ "xyz.openbmc_project.Logging.Create", "Create");
+ // Signature is ssa{ss}
+ method.append(error);
+ method.append("xyz.openbmc_project.Logging.Entry.Level.Critical");
+ method.append(std::array<std::pair<std::string, std::string>, 1>(
+ {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result})}));
+ try
+ {
+ this->bus.call_noreply(method);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("Failed to create systemd target error",
+ entry("ERROR=%s", error.c_str()),
+ entry("RESULT=%s", result.c_str()),
+ entry("SDBUSERR=%s", e.what()));
+ }
+}
+
+const std::string* SystemdTargetLogging::processError(const std::string& unit,
+ const std::string& result)
+{
+ auto targetEntry = this->targetData.find(unit);
+ if (targetEntry != this->targetData.end())
+ {
+ // Check if its result matches any of our monitored errors
+ if (std::find(targetEntry->second.errorsToMonitor.begin(),
+ targetEntry->second.errorsToMonitor.end(),
+ result) != targetEntry->second.errorsToMonitor.end())
+ {
+ log<level::INFO>("Monitored systemd unit has hit an error",
+ entry("UNIT=%s", unit.c_str()),
+ entry("RESULT=%s", result.c_str()));
+ return (&targetEntry->second.errorToLog);
+ }
+ }
+ return {nullptr};
+}
+
+void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg)
+{
+ uint32_t id;
+ sdbusplus::message::object_path objPath;
+ std::string unit{};
+ std::string result{};
+
+ msg.read(id, objPath, unit, result);
+
+ // In most cases it will just be success, in which case just return
+ if (result != "done")
+ {
+ const std::string* error = processError(unit, result);
+
+ // If this is a monitored error then log it
+ if (error)
+ {
+ logError(*error, result);
+ }
+ }
+ return;
+}
+
+void SystemdTargetLogging::subscribeToSystemdSignals()
+{
+ auto method = this->bus.new_method_call(
+ "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager", "Subscribe");
+
+ try
+ {
+ this->bus.call(method);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("Failed to subscribe to systemd signals",
+ entry("SDBUSERR=%s", e.what()));
+ elog<InternalFailure>();
+ }
+
+ return;
+}
+
+} // namespace manager
+} // namespace state
+} // namespace phosphor