Update Trigger Actions implementation

Dbus trigger action names were modified to reflect separation of
Telemetry Service from Redfish:
- LogToLogService is renamed to LogToJournal,
- RedfishEvent was renamed to LogToRedfishEventLog

Both of those logging actions, now also include trigger id and threshold
name. Threshold naming logic:
- For discrete triggers, it can be specified by user, if left empty it
  will be changed to "{Severity} condition".
- Numeric triggers have no way of naming threshold, instead its type
  will be converted to string, example "UpperWarning"
- Discrete OnChange threshold will always be named "OnChange"

Additionally, defect was found with timestamp attached to Trigger Logs:
it was a steady_clock timestamp instead of system_clock. The function
which was supposed to format it was also working incorrectly, and was
improved to work with milliseconds. This change required major refactor
of unit tests, especially for numeric threshold.

Testing done:
- LogToJournal action is working properly,
- LogToRedfishEventLog action is working properly,
- UTs are passing.

Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
Change-Id: Iae2490682f0e9e2a610b45fd8af5cc5e21e66f35
diff --git a/src/discrete_threshold.cpp b/src/discrete_threshold.cpp
index 1bb250f..ba915b1 100644
--- a/src/discrete_threshold.cpp
+++ b/src/discrete_threshold.cpp
@@ -5,15 +5,18 @@
 #include <phosphor-logging/log.hpp>
 
 DiscreteThreshold::DiscreteThreshold(
-    boost::asio::io_context& ioc, Sensors sensorsIn,
+    boost::asio::io_context& ioc, const std::string& triggerIdIn,
+    Sensors sensorsIn,
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
     Milliseconds dwellTimeIn, const std::string& thresholdValueIn,
-    const std::string& nameIn, const discrete::Severity severityIn) :
+    const std::string& nameIn, const discrete::Severity severityIn,
+    std::unique_ptr<interfaces::Clock> clockIn) :
     ioc(ioc),
-    actions(std::move(actionsIn)), dwellTime(dwellTimeIn),
-    thresholdValue(thresholdValueIn),
-    numericThresholdValue(utils::stodStrict(thresholdValue)), name(nameIn),
-    severity(severityIn)
+    triggerId(triggerIdIn), actions(std::move(actionsIn)),
+    dwellTime(dwellTimeIn), thresholdValue(thresholdValueIn),
+    numericThresholdValue(utils::stodStrict(thresholdValue)),
+    severity(severityIn), name(getNonEmptyName(nameIn)),
+    clock(std::move(clockIn))
 {
     for (const auto& sensor : sensorsIn)
     {
@@ -56,12 +59,12 @@
     }
     else if (value == numericThresholdValue)
     {
-        startTimer(details, timestamp, value);
+        startTimer(details, value);
     }
 }
 
 void DiscreteThreshold::startTimer(DiscreteThreshold::ThresholdDetail& details,
-                                   Milliseconds timestamp, double value)
+                                   double value)
 {
     const auto& sensorName = details.sensorName;
     auto& dwell = details.dwell;
@@ -69,13 +72,13 @@
 
     if (dwellTime == Milliseconds::zero())
     {
-        commit(sensorName, timestamp, value);
+        commit(sensorName, value);
     }
     else
     {
         dwell = true;
         timer.expires_after(dwellTime);
-        timer.async_wait([this, &sensorName, &dwell, timestamp,
+        timer.async_wait([this, &sensorName, &dwell,
                           value](const boost::system::error_code ec) {
             if (ec)
             {
@@ -83,18 +86,19 @@
                     "Timer has been canceled");
                 return;
             }
-            commit(sensorName, timestamp, value);
+            commit(sensorName, value);
             dwell = false;
         });
     }
 }
 
-void DiscreteThreshold::commit(const std::string& sensorName,
-                               Milliseconds timestamp, double value)
+void DiscreteThreshold::commit(const std::string& sensorName, double value)
 {
+    Milliseconds timestamp = clock->systemTimestamp();
     for (const auto& action : actions)
     {
-        action->commit(sensorName, timestamp, value);
+        action->commit(triggerId, std::cref(name), sensorName, timestamp,
+                       thresholdValue);
     }
 }
 
@@ -103,3 +107,12 @@
     return discrete::LabeledThresholdParam(name, severity, dwellTime.count(),
                                            thresholdValue);
 }
+
+std::string DiscreteThreshold::getNonEmptyName(const std::string& nameIn) const
+{
+    if (nameIn.empty())
+    {
+        return discrete::severityToString(severity) + " condition";
+    }
+    return nameIn;
+}
diff --git a/src/discrete_threshold.hpp b/src/discrete_threshold.hpp
index 545a980..a471027 100644
--- a/src/discrete_threshold.hpp
+++ b/src/discrete_threshold.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "interfaces/clock.hpp"
 #include "interfaces/sensor.hpp"
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
@@ -22,10 +23,12 @@
 {
   public:
     DiscreteThreshold(
-        boost::asio::io_context& ioc, Sensors sensors,
+        boost::asio::io_context& ioc, const std::string& triggerId,
+        Sensors sensors,
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions,
         Milliseconds dwellTime, const std::string& thresholdValue,
-        const std::string& name, const discrete::Severity severity);
+        const std::string& name, const discrete::Severity severity,
+        std::unique_ptr<interfaces::Clock> clock);
     DiscreteThreshold(const DiscreteThreshold&) = delete;
     DiscreteThreshold(DiscreteThreshold&&) = delete;
 
@@ -36,13 +39,15 @@
 
   private:
     boost::asio::io_context& ioc;
+    const std::string& triggerId;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
     const Milliseconds dwellTime;
     const std::string thresholdValue;
     const double numericThresholdValue;
-    const std::string name;
     const discrete::Severity severity;
+    const std::string name;
     bool initialized = false;
+    std::unique_ptr<interfaces::Clock> clock;
 
     struct ThresholdDetail
     {
@@ -63,8 +68,9 @@
 
     friend ThresholdOperations;
 
-    void startTimer(ThresholdDetail&, Milliseconds, double);
-    void commit(const std::string&, Milliseconds, double);
+    void startTimer(ThresholdDetail&, double);
+    void commit(const std::string&, double);
     ThresholdDetail& getDetails(const interfaces::Sensor& sensor);
     std::shared_ptr<ThresholdDetail> makeDetails(const std::string& sensorName);
+    std::string getNonEmptyName(const std::string& nameIn) const;
 };
diff --git a/src/interfaces/trigger_action.hpp b/src/interfaces/trigger_action.hpp
index 437a79f..7e0babd 100644
--- a/src/interfaces/trigger_action.hpp
+++ b/src/interfaces/trigger_action.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "types/duration_types.hpp"
+#include "types/trigger_types.hpp"
 
 #include <cstdint>
 #include <string>
@@ -13,7 +14,10 @@
   public:
     virtual ~TriggerAction() = default;
 
-    virtual void commit(const std::string& id, Milliseconds timestamp,
-                        double value) = 0;
+    virtual void commit(const std::string& triggerId,
+                        const ThresholdName thresholdName,
+                        const std::string& sensorId,
+                        const Milliseconds timestamp,
+                        const TriggerValue value) = 0;
 };
 } // namespace interfaces
diff --git a/src/interfaces/trigger_factory.hpp b/src/interfaces/trigger_factory.hpp
index 0e7ac7f..947af43 100644
--- a/src/interfaces/trigger_factory.hpp
+++ b/src/interfaces/trigger_factory.hpp
@@ -40,6 +40,7 @@
 
     virtual void updateThresholds(
         std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+        const std::string& triggerId,
         const std::vector<::TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
diff --git a/src/numeric_threshold.cpp b/src/numeric_threshold.cpp
index cb6dbdd..9bda509 100644
--- a/src/numeric_threshold.cpp
+++ b/src/numeric_threshold.cpp
@@ -3,13 +3,16 @@
 #include <phosphor-logging/log.hpp>
 
 NumericThreshold::NumericThreshold(
-    boost::asio::io_context& ioc, Sensors sensorsIn,
+    boost::asio::io_context& ioc, const std::string& triggerIdIn,
+    Sensors sensorsIn,
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
     Milliseconds dwellTimeIn, numeric::Direction directionIn,
-    double thresholdValueIn, numeric::Type typeIn) :
+    double thresholdValueIn, numeric::Type typeIn,
+    std::unique_ptr<interfaces::Clock> clockIn) :
     ioc(ioc),
-    actions(std::move(actionsIn)), dwellTime(dwellTimeIn),
-    direction(directionIn), thresholdValue(thresholdValueIn), type(typeIn)
+    triggerId(triggerIdIn), actions(std::move(actionsIn)),
+    dwellTime(dwellTimeIn), direction(directionIn),
+    thresholdValue(thresholdValueIn), type(typeIn), clock(std::move(clockIn))
 {
     for (const auto& sensor : sensorsIn)
     {
@@ -57,14 +60,14 @@
         (direction == numeric::Direction::increasing && increasing) ||
         (direction == numeric::Direction::either && (increasing || decreasing)))
     {
-        startTimer(details, timestamp, value);
+        startTimer(details, value);
     }
 
     prevValue = value;
 }
 
 void NumericThreshold::startTimer(NumericThreshold::ThresholdDetail& details,
-                                  Milliseconds timestamp, double value)
+                                  double value)
 {
     const auto& sensorName = details.sensorName;
     auto& dwell = details.dwell;
@@ -72,13 +75,13 @@
 
     if (dwellTime == Milliseconds::zero())
     {
-        commit(sensorName, timestamp, value);
+        commit(sensorName, value);
     }
     else
     {
         dwell = true;
         timer.expires_after(dwellTime);
-        timer.async_wait([this, &sensorName, &dwell, timestamp,
+        timer.async_wait([this, &sensorName, &dwell,
                           value](const boost::system::error_code ec) {
             if (ec)
             {
@@ -86,18 +89,18 @@
                     "Timer has been canceled");
                 return;
             }
-            commit(sensorName, timestamp, value);
+            commit(sensorName, value);
             dwell = false;
         });
     }
 }
 
-void NumericThreshold::commit(const std::string& sensorName,
-                              Milliseconds timestamp, double value)
+void NumericThreshold::commit(const std::string& sensorName, double value)
 {
+    Milliseconds timestamp = clock->systemTimestamp();
     for (const auto& action : actions)
     {
-        action->commit(sensorName, timestamp, value);
+        action->commit(triggerId, std::nullopt, sensorName, timestamp, value);
     }
 }
 
diff --git a/src/numeric_threshold.hpp b/src/numeric_threshold.hpp
index ecf3d6a..d70729a 100644
--- a/src/numeric_threshold.hpp
+++ b/src/numeric_threshold.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "interfaces/clock.hpp"
 #include "interfaces/sensor.hpp"
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
@@ -22,10 +23,12 @@
 {
   public:
     NumericThreshold(
-        boost::asio::io_context& ioc, Sensors sensors,
+        boost::asio::io_context& ioc, const std::string& triggerId,
+        Sensors sensors,
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions,
         Milliseconds dwellTime, numeric::Direction direction,
-        double thresholdValue, numeric::Type type);
+        double thresholdValue, numeric::Type type,
+        std::unique_ptr<interfaces::Clock> clock);
     ~NumericThreshold()
     {}
 
@@ -36,12 +39,14 @@
 
   private:
     boost::asio::io_context& ioc;
+    const std::string& triggerId;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
     const Milliseconds dwellTime;
     const numeric::Direction direction;
     const double thresholdValue;
     const numeric::Type type;
     bool initialized = false;
+    std::unique_ptr<interfaces::Clock> clock;
 
     struct ThresholdDetail
     {
@@ -63,8 +68,8 @@
 
     friend ThresholdOperations;
 
-    void startTimer(ThresholdDetail&, Milliseconds, double);
-    void commit(const std::string&, Milliseconds, double);
+    void startTimer(ThresholdDetail&, double);
+    void commit(const std::string&, double);
     ThresholdDetail& getDetails(const interfaces::Sensor& sensor);
     std::shared_ptr<ThresholdDetail> makeDetails(const std::string& sensorName);
 };
diff --git a/src/on_change_threshold.cpp b/src/on_change_threshold.cpp
index eea8978..206deb2 100644
--- a/src/on_change_threshold.cpp
+++ b/src/on_change_threshold.cpp
@@ -3,10 +3,12 @@
 #include <phosphor-logging/log.hpp>
 
 OnChangeThreshold::OnChangeThreshold(
-    Sensors sensorsIn,
-    std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn) :
-    sensors(std::move(sensorsIn)),
-    actions(std::move(actionsIn))
+    const std::string& triggerIdIn, Sensors sensorsIn,
+    std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
+    std::unique_ptr<interfaces::Clock> clockIn) :
+    triggerId(triggerIdIn),
+    sensors(std::move(sensorsIn)), actions(std::move(actionsIn)),
+    clock(std::move(clockIn))
 {}
 
 void OnChangeThreshold::initialize()
@@ -59,15 +61,15 @@
         return;
     }
 
-    commit(sensor.getName(), timestamp, value);
+    commit(sensor.getName(), value);
 }
 
-void OnChangeThreshold::commit(const std::string& sensorName,
-                               Milliseconds timestamp, double value)
+void OnChangeThreshold::commit(const std::string& sensorName, double value)
 {
+    Milliseconds timestamp = clock->systemTimestamp();
     for (const auto& action : actions)
     {
-        action->commit(sensorName, timestamp, value);
+        action->commit(triggerId, std::nullopt, sensorName, timestamp, value);
     }
 }
 
diff --git a/src/on_change_threshold.hpp b/src/on_change_threshold.hpp
index 1d4a4d0..a19a86f 100644
--- a/src/on_change_threshold.hpp
+++ b/src/on_change_threshold.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "interfaces/clock.hpp"
 #include "interfaces/sensor.hpp"
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
@@ -19,8 +20,9 @@
 {
   public:
     OnChangeThreshold(
-        Sensors sensors,
-        std::vector<std::unique_ptr<interfaces::TriggerAction>> actions);
+        const std::string& triggerId, Sensors sensors,
+        std::vector<std::unique_ptr<interfaces::TriggerAction>> actions,
+        std::unique_ptr<interfaces::Clock> clock);
     ~OnChangeThreshold()
     {}
 
@@ -30,10 +32,12 @@
     void updateSensors(Sensors newSensors) override;
 
   private:
+    const std::string& triggerId;
     Sensors sensors;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
     bool initialized = false;
     bool isFirstReading = true;
+    std::unique_ptr<interfaces::Clock> clock;
 
-    void commit(const std::string&, Milliseconds, double);
+    void commit(const std::string&, double);
 };
diff --git a/src/trigger.cpp b/src/trigger.cpp
index 485f2f9..ab48281 100644
--- a/src/trigger.cpp
+++ b/src/trigger.cpp
@@ -14,18 +14,18 @@
 Trigger::Trigger(
     boost::asio::io_context& ioc,
     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
-    const std::string& idIn, const std::string& nameIn,
+    TriggerId&& idIn, const std::string& nameIn,
     const std::vector<TriggerAction>& triggerActionsIn,
     const std::shared_ptr<std::vector<std::string>> reportIdsIn,
     std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
     interfaces::TriggerManager& triggerManager,
     interfaces::JsonStorage& triggerStorageIn,
     const interfaces::TriggerFactory& triggerFactory, Sensors sensorsIn) :
-    id(idIn),
+    id(std::move(idIn)),
     name(nameIn), triggerActions(std::move(triggerActionsIn)),
-    path(triggerDir + id), reportIds(std::move(reportIdsIn)),
+    path(triggerDir + *id), reportIds(std::move(reportIdsIn)),
     thresholds(std::move(thresholdsIn)),
-    fileName(std::to_string(std::hash<std::string>{}(id))),
+    fileName(std::to_string(std::hash<std::string>{}(*id))),
     triggerStorage(triggerStorageIn), sensors(std::move(sensorsIn)),
     messanger(ioc)
 {
@@ -37,7 +37,7 @@
                     triggerStorage.remove(fileName);
                 }
                 messanger.send(messages::TriggerPresenceChangedInd{
-                    messages::Presence::Removed, id, {}});
+                    messages::Presence::Removed, *id, {}});
                 boost::asio::post(ioc, [this, &triggerManager] {
                     triggerManager.removeTrigger(this);
                 });
@@ -74,9 +74,9 @@
                 [this, &triggerFactory](auto newVal, auto& oldVal) {
                     auto newThresholdParams = std::visit(
                         utils::ToLabeledThresholdParamConversion(), newVal);
-                    triggerFactory.updateThresholds(thresholds, triggerActions,
-                                                    reportIds, sensors,
-                                                    newThresholdParams);
+                    triggerFactory.updateThresholds(
+                        thresholds, *id, triggerActions, reportIds, sensors,
+                        newThresholdParams);
                     oldVal = std::move(newVal);
                     return 1;
                 },
@@ -110,7 +110,7 @@
                     TriggerManager::verifyReportIds(newVal);
                     *reportIds = newVal;
                     messanger.send(messages::TriggerPresenceChangedInd{
-                        messages::Presence::Exist, id, *reportIds});
+                        messages::Presence::Exist, *id, *reportIds});
                     oldVal = std::move(newVal);
                     return 1;
                 },
@@ -147,12 +147,12 @@
         [this](const auto& msg) {
             if (utils::contains(*reportIds, msg.reportId))
             {
-                messanger.send(messages::CollectTriggerIdResp{id});
+                messanger.send(messages::CollectTriggerIdResp{*id});
             }
         });
 
     messanger.send(messages::TriggerPresenceChangedInd{
-        messages::Presence::Exist, id, *reportIds});
+        messages::Presence::Exist, *id, *reportIds});
 }
 
 bool Trigger::storeConfiguration() const
@@ -166,7 +166,7 @@
                        fromLabeledThresholdParam(getLabeledThresholds()));
 
         data["Version"] = triggerVersion;
-        data["Id"] = id;
+        data["Id"] = *id;
         data["Name"] = name;
         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
         data["TriggerActions"] =
diff --git a/src/trigger.hpp b/src/trigger.hpp
index 6bd2556..832a277 100644
--- a/src/trigger.hpp
+++ b/src/trigger.hpp
@@ -18,7 +18,7 @@
   public:
     Trigger(boost::asio::io_context& ioc,
             const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
-            const std::string& id, const std::string& name,
+            TriggerId&& id, const std::string& name,
             const std::vector<TriggerAction>& triggerActions,
             const std::shared_ptr<std::vector<std::string>> reportIds,
             std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholds,
@@ -34,7 +34,7 @@
 
     std::string getId() const override
     {
-        return id;
+        return *id;
     }
 
     std::string getPath() const override
@@ -49,7 +49,7 @@
     std::vector<LabeledThresholdParam> getLabeledThresholds() const;
     bool isDiscreate() const;
 
-    std::string id;
+    const TriggerId id;
     std::string name;
     std::vector<TriggerAction> triggerActions;
     std::string path;
@@ -71,5 +71,5 @@
         "/xyz/openbmc_project/Telemetry/Triggers/";
     static constexpr const char* deleteIfaceName =
         "xyz.openbmc_project.Object.Delete";
-    static constexpr size_t triggerVersion = 1;
+    static constexpr size_t triggerVersion = 2;
 };
diff --git a/src/trigger_actions.cpp b/src/trigger_actions.cpp
index c840422..75aab50 100644
--- a/src/trigger_actions.cpp
+++ b/src/trigger_actions.cpp
@@ -2,11 +2,14 @@
 
 #include "messages/update_report_ind.hpp"
 #include "types/trigger_types.hpp"
+#include "utils/clock.hpp"
 #include "utils/messanger.hpp"
 
 #include <phosphor-logging/log.hpp>
 
 #include <ctime>
+#include <iomanip>
+#include <sstream>
 
 namespace action
 {
@@ -15,15 +18,12 @@
 {
 std::string timestampToString(Milliseconds timestamp)
 {
-    std::time_t t = static_cast<time_t>(timestamp.count());
-    std::array<char, sizeof("YYYY-MM-DDThh:mm:ssZ")> buf = {};
-    size_t size =
-        std::strftime(buf.data(), buf.size(), "%FT%TZ", std::gmtime(&t));
-    if (size == 0)
-    {
-        throw std::runtime_error("Failed to parse timestamp to string");
-    }
-    return std::string(buf.data(), size);
+    std::time_t t = static_cast<time_t>(
+        std::chrono::duration_cast<std::chrono::seconds>(timestamp).count());
+    std::stringstream ss;
+    ss << std::put_time(std::gmtime(&t), "%FT%T.") << std::setw(3)
+       << std::setfill('0') << timestamp.count() % 1000 << 'Z';
+    return ss.str();
 }
 } // namespace
 
@@ -43,44 +43,60 @@
     throw std::runtime_error("Invalid value");
 }
 
-void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+void LogToJournal::commit(const std::string& triggerId,
+                          const ThresholdName thresholdNameInIn,
+                          const std::string& sensorName,
+                          const Milliseconds timestamp,
+                          const TriggerValue triggerValue)
 {
-    std::string msg = ::numeric::typeToString(type) +
-                      " numeric threshold condition is met on sensor " +
-                      sensorName + ", recorded value " + std::to_string(value) +
-                      ", timestamp " + timestampToString(timestamp) +
-                      ", direction " +
-                      std::string(getDirection(value, threshold));
+    double value = std::get<double>(triggerValue);
+    std::string thresholdName = ::numeric::typeToString(type);
+    auto direction = getDirection(value, threshold);
+
+    std::string msg = "Numeric threshold '" + thresholdName + "' of trigger '" +
+                      triggerId + "' is crossed on sensor " + sensorName +
+                      ", recorded value: " + std::to_string(value) +
+                      ", crossing direction: " + direction +
+                      ", timestamp: " + timestampToString(timestamp);
 
     phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
 }
 
-const char* LogToRedfish::getMessageId() const
+const char* LogToRedfishEventLog::getRedfishMessageId() const
 {
     switch (type)
     {
         case ::numeric::Type::upperCritical:
-            return "OpenBMC.0.1.0.NumericThresholdUpperCritical";
+            return redfish_message_ids::TriggerNumericCritical;
         case ::numeric::Type::lowerCritical:
-            return "OpenBMC.0.1.0.NumericThresholdLowerCritical";
+            return redfish_message_ids::TriggerNumericCritical;
         case ::numeric::Type::upperWarning:
-            return "OpenBMC.0.1.0.NumericThresholdUpperWarning";
+            return redfish_message_ids::TriggerNumericWarning;
         case ::numeric::Type::lowerWarning:
-            return "OpenBMC.0.1.0.NumericThresholdLowerWarning";
+            return redfish_message_ids::TriggerNumericWarning;
     }
     throw std::runtime_error("Invalid type");
 }
 
-void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+void LogToRedfishEventLog::commit(const std::string& triggerId,
+                                  const ThresholdName thresholdNameInIn,
+                                  const std::string& sensorName,
+                                  const Milliseconds timestamp,
+                                  const TriggerValue triggerValue)
 {
+    double value = std::get<double>(triggerValue);
+    std::string thresholdName = ::numeric::typeToString(type);
+    auto direction = getDirection(value, threshold);
+    auto timestampStr = timestampToString(timestamp);
+
     phosphor::logging::log<phosphor::logging::level::INFO>(
-        "Threshold value is exceeded",
-        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()),
-        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu,%s",
-                                 sensorName.c_str(), value, timestamp.count(),
-                                 getDirection(value, threshold)));
+        "Logging numeric trigger action to Redfish Event Log.",
+        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
+                                 getRedfishMessageId()),
+        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s,%f,%s,%s",
+                                 thresholdName.c_str(), triggerId.c_str(),
+                                 sensorName.c_str(), value, direction,
+                                 timestampStr.c_str()));
 }
 
 void fillActions(
@@ -94,16 +110,16 @@
     {
         switch (actionType)
         {
-            case TriggerAction::LogToLogService:
+            case TriggerAction::LogToJournal:
             {
                 actionsIf.emplace_back(
                     std::make_unique<LogToJournal>(type, thresholdValue));
                 break;
             }
-            case TriggerAction::RedfishEvent:
+            case TriggerAction::LogToRedfishEventLog:
             {
-                actionsIf.emplace_back(
-                    std::make_unique<LogToRedfish>(type, thresholdValue));
+                actionsIf.emplace_back(std::make_unique<LogToRedfishEventLog>(
+                    type, thresholdValue));
                 break;
             }
             case TriggerAction::UpdateReport:
@@ -120,39 +136,55 @@
 
 namespace discrete
 {
-void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+
+void LogToJournal::commit(const std::string& triggerId,
+                          const ThresholdName thresholdNameIn,
+                          const std::string& sensorName,
+                          const Milliseconds timestamp,
+                          const TriggerValue triggerValue)
 {
-    std::string msg = ::discrete::severityToString(severity) +
-                      " discrete threshold condition is met on sensor " +
-                      sensorName + ", recorded value " + std::to_string(value) +
-                      ", timestamp " + timestampToString(timestamp);
+    auto value = std::get<std::string>(triggerValue);
+
+    std::string msg = "Discrete condition '" + thresholdNameIn->get() +
+                      "' of trigger '" + triggerId + "' is met on sensor " +
+                      sensorName + ", recorded value: " + value +
+                      ", severity: " + ::discrete::severityToString(severity) +
+                      ", timestamp: " + timestampToString(timestamp);
 
     phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
 }
 
-const char* LogToRedfish::getMessageId() const
+const char* LogToRedfishEventLog::getRedfishMessageId() const
 {
     switch (severity)
     {
         case ::discrete::Severity::ok:
-            return "OpenBMC.0.1.0.DiscreteThresholdOk";
+            return redfish_message_ids::TriggerDiscreteOK;
         case ::discrete::Severity::warning:
-            return "OpenBMC.0.1.0.DiscreteThresholdWarning";
+            return redfish_message_ids::TriggerDiscreteWarning;
         case ::discrete::Severity::critical:
-            return "OpenBMC.0.1.0.DiscreteThresholdCritical";
+            return redfish_message_ids::TriggerDiscreteCritical;
     }
     throw std::runtime_error("Invalid severity");
 }
 
-void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+void LogToRedfishEventLog::commit(const std::string& triggerId,
+                                  const ThresholdName thresholdNameIn,
+                                  const std::string& sensorName,
+                                  const Milliseconds timestamp,
+                                  const TriggerValue triggerValue)
 {
+    auto value = std::get<std::string>(triggerValue);
+    auto timestampStr = timestampToString(timestamp);
+
     phosphor::logging::log<phosphor::logging::level::INFO>(
-        "Discrete treshold condition is met",
-        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", getMessageId()),
-        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu",
-                                 sensorName.c_str(), value, timestamp.count()));
+        "Logging discrete trigger action to Redfish Event Log.",
+        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
+                                 getRedfishMessageId()),
+        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s,%s,%s",
+                                 thresholdNameIn->get().c_str(),
+                                 triggerId.c_str(), sensorName.c_str(),
+                                 value.c_str(), timestampStr.c_str()));
 }
 
 void fillActions(
@@ -166,16 +198,16 @@
     {
         switch (actionType)
         {
-            case TriggerAction::LogToLogService:
+            case TriggerAction::LogToJournal:
             {
                 actionsIf.emplace_back(
                     std::make_unique<LogToJournal>(severity));
                 break;
             }
-            case TriggerAction::RedfishEvent:
+            case TriggerAction::LogToRedfishEventLog:
             {
                 actionsIf.emplace_back(
-                    std::make_unique<LogToRedfish>(severity));
+                    std::make_unique<LogToRedfishEventLog>(severity));
                 break;
             }
             case TriggerAction::UpdateReport:
@@ -190,25 +222,38 @@
 
 namespace onChange
 {
-void LogToJournal::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+void LogToJournal::commit(const std::string& triggerId,
+                          const ThresholdName thresholdNameIn,
+                          const std::string& sensorName,
+                          const Milliseconds timestamp,
+                          const TriggerValue triggerValue)
 {
-    std::string msg = "Value changed on sensor " + sensorName +
-                      ", recorded value " + std::to_string(value) +
-                      ", timestamp " + timestampToString(timestamp);
+    auto value = triggerValueToString(triggerValue);
+    std::string msg = "Discrete condition 'OnChange' of trigger '" + triggerId +
+                      "' is met on sensor: " + sensorName +
+                      ", recorded value: " + value +
+                      ", timestamp: " + timestampToString(timestamp);
 
     phosphor::logging::log<phosphor::logging::level::INFO>(msg.c_str());
 }
 
-void LogToRedfish::commit(const std::string& sensorName, Milliseconds timestamp,
-                          double value)
+void LogToRedfishEventLog::commit(const std::string& triggerId,
+                                  const ThresholdName thresholdNameIn,
+                                  const std::string& sensorName,
+                                  const Milliseconds timestamp,
+                                  const TriggerValue triggerValue)
 {
-    const char* messageId = "OpenBMC.0.1.0.DiscreteThresholdOnChange";
+    auto value = triggerValueToString(triggerValue);
+    auto timestampStr = timestampToString(timestamp);
+
     phosphor::logging::log<phosphor::logging::level::INFO>(
-        "Uncondtional discrete threshold triggered",
-        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageId),
-        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%f,%llu",
-                                 sensorName.c_str(), value, timestamp.count()));
+        "Logging onChange discrete trigger action to Redfish Event Log.",
+        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
+                                 redfish_message_ids::TriggerDiscreteOK),
+        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s,%s,%s,%s,%s",
+                                 "OnChange", triggerId.c_str(),
+                                 sensorName.c_str(), value.c_str(),
+                                 timestampStr.c_str()));
 }
 
 void fillActions(
@@ -221,14 +266,15 @@
     {
         switch (actionType)
         {
-            case TriggerAction::LogToLogService:
+            case TriggerAction::LogToJournal:
             {
                 actionsIf.emplace_back(std::make_unique<LogToJournal>());
                 break;
             }
-            case TriggerAction::RedfishEvent:
+            case TriggerAction::LogToRedfishEventLog:
             {
-                actionsIf.emplace_back(std::make_unique<LogToRedfish>());
+                actionsIf.emplace_back(
+                    std::make_unique<LogToRedfishEventLog>());
                 break;
             }
             case TriggerAction::UpdateReport:
@@ -243,7 +289,11 @@
 } // namespace onChange
 } // namespace discrete
 
-void UpdateReport::commit(const std::string&, Milliseconds, double)
+void UpdateReport::commit(const std::string& triggerId,
+                          const ThresholdName thresholdNameIn,
+                          const std::string& sensorName,
+                          const Milliseconds timestamp,
+                          const TriggerValue triggerValue)
 {
     if (reportIds->empty())
     {
diff --git a/src/trigger_actions.hpp b/src/trigger_actions.hpp
index fdf07fe..a74cc7a 100644
--- a/src/trigger_actions.hpp
+++ b/src/trigger_actions.hpp
@@ -8,6 +8,19 @@
 namespace action
 {
 
+namespace redfish_message_ids
+{
+constexpr const char* TriggerNumericWarning =
+    "OpenBMC.0.1.TriggerNumericWarning";
+constexpr const char* TriggerNumericCritical =
+    "OpenBMC.0.1.TriggerNumericCritical";
+constexpr const char* TriggerDiscreteOK = "OpenBMC.0.1.TriggerDiscreteOK";
+constexpr const char* TriggerDiscreteWarning =
+    "OpenBMC.0.1.TriggerDiscreteWarning";
+constexpr const char* TriggerDiscreteCritical =
+    "OpenBMC.0.1.TriggerDiscreteCritical";
+} // namespace redfish_message_ids
+
 namespace numeric
 {
 class LogToJournal : public interfaces::TriggerAction
@@ -16,28 +29,31 @@
     LogToJournal(::numeric::Type type, double val) : type(type), threshold(val)
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 
   private:
-    ::numeric::Type type;
-    double threshold;
+    const ::numeric::Type type;
+    const double threshold;
 };
 
-class LogToRedfish : public interfaces::TriggerAction
+class LogToRedfishEventLog : public interfaces::TriggerAction
 {
   public:
-    LogToRedfish(::numeric::Type type, double val) : type(type), threshold(val)
+    LogToRedfishEventLog(::numeric::Type type, double val) :
+        type(type), threshold(val)
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 
   private:
-    ::numeric::Type type;
-    double threshold;
+    const ::numeric::Type type;
+    const double threshold;
 
-    const char* getMessageId() const;
+    const char* getRedfishMessageId() const;
 };
 
 void fillActions(
@@ -55,26 +71,29 @@
     explicit LogToJournal(::discrete::Severity severity) : severity(severity)
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 
   private:
-    ::discrete::Severity severity;
+    const ::discrete::Severity severity;
 };
 
-class LogToRedfish : public interfaces::TriggerAction
+class LogToRedfishEventLog : public interfaces::TriggerAction
 {
   public:
-    explicit LogToRedfish(::discrete::Severity severity) : severity(severity)
+    explicit LogToRedfishEventLog(::discrete::Severity severity) :
+        severity(severity)
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 
   private:
-    ::discrete::Severity severity;
+    const ::discrete::Severity severity;
 
-    const char* getMessageId() const;
+    const char* getRedfishMessageId() const;
 };
 
 void fillActions(
@@ -91,18 +110,20 @@
     LogToJournal()
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 };
 
-class LogToRedfish : public interfaces::TriggerAction
+class LogToRedfishEventLog : public interfaces::TriggerAction
 {
   public:
-    LogToRedfish()
+    LogToRedfishEventLog()
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 };
 
 void fillActions(
@@ -122,8 +143,9 @@
         reportIds(std::move(ids))
     {}
 
-    void commit(const std::string& id, Milliseconds timestamp,
-                double value) override;
+    void commit(const std::string& triggerId, const ThresholdName thresholdName,
+                const std::string& sensorName, const Milliseconds timestamp,
+                const TriggerValue value) override;
 
   private:
     boost::asio::io_context& ioc;
diff --git a/src/trigger_factory.cpp b/src/trigger_factory.cpp
index 6c9ceb9..615d42d 100644
--- a/src/trigger_factory.cpp
+++ b/src/trigger_factory.cpp
@@ -6,6 +6,7 @@
 #include "sensor.hpp"
 #include "trigger.hpp"
 #include "trigger_actions.hpp"
+#include "utils/clock.hpp"
 #include "utils/dbus_mapper.hpp"
 #include "utils/transform.hpp"
 
@@ -21,6 +22,7 @@
 
 void TriggerFactory::updateDiscreteThresholds(
     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors,
@@ -57,16 +59,16 @@
                 continue;
             }
 
-            makeDiscreteThreshold(newThresholds, triggerActions, reportIds,
-                                  sensors, labeledThresholdParam);
+            makeDiscreteThreshold(newThresholds, triggerId, triggerActions,
+                                  reportIds, sensors, labeledThresholdParam);
         }
     }
     else
     {
         for (const auto& labeledThresholdParam : newParams)
         {
-            makeDiscreteThreshold(newThresholds, triggerActions, reportIds,
-                                  sensors, labeledThresholdParam);
+            makeDiscreteThreshold(newThresholds, triggerId, triggerActions,
+                                  reportIds, sensors, labeledThresholdParam);
         }
     }
     if (newParams.empty())
@@ -77,8 +79,8 @@
         }
         else
         {
-            makeOnChangeThreshold(newThresholds, triggerActions, reportIds,
-                                  sensors);
+            makeOnChangeThreshold(newThresholds, triggerId, triggerActions,
+                                  reportIds, sensors);
         }
     }
     currentThresholds = std::move(newThresholds);
@@ -86,6 +88,7 @@
 
 void TriggerFactory::updateNumericThresholds(
     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors,
@@ -112,14 +115,15 @@
             continue;
         }
 
-        makeNumericThreshold(newThresholds, triggerActions, reportIds, sensors,
-                             labeledThresholdParam);
+        makeNumericThreshold(newThresholds, triggerId, triggerActions,
+                             reportIds, sensors, labeledThresholdParam);
     }
     currentThresholds = std::move(newThresholds);
 }
 
 void TriggerFactory::updateThresholds(
     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors,
@@ -130,21 +134,24 @@
         const auto& labeledDiscreteThresholdParams =
             std::get<std::vector<discrete::LabeledThresholdParam>>(newParams);
 
-        updateDiscreteThresholds(currentThresholds, triggerActions, reportIds,
-                                 sensors, labeledDiscreteThresholdParams);
+        updateDiscreteThresholds(currentThresholds, triggerId, triggerActions,
+                                 reportIds, sensors,
+                                 labeledDiscreteThresholdParams);
     }
     else
     {
         const auto& labeledNumericThresholdParams =
             std::get<std::vector<numeric::LabeledThresholdParam>>(newParams);
 
-        updateNumericThresholds(currentThresholds, triggerActions, reportIds,
-                                sensors, labeledNumericThresholdParams);
+        updateNumericThresholds(currentThresholds, triggerId, triggerActions,
+                                reportIds, sensors,
+                                labeledNumericThresholdParams);
     }
 }
 
 void TriggerFactory::makeDiscreteThreshold(
     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors,
@@ -152,21 +159,24 @@
 {
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
 
-    std::string thresholdName = thresholdParam.at_label<ts::UserId>();
+    const std::string& thresholdName = thresholdParam.at_label<ts::UserId>();
     discrete::Severity severity = thresholdParam.at_label<ts::Severity>();
     auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>());
-    std::string thresholdValue = thresholdParam.at_label<ts::ThresholdValue>();
+    const std::string& thresholdValue =
+        thresholdParam.at_label<ts::ThresholdValue>();
 
     action::discrete::fillActions(actions, triggerActions, severity,
                                   bus->get_io_context(), reportIds);
 
     thresholds.emplace_back(std::make_shared<DiscreteThreshold>(
-        bus->get_io_context(), sensors, std::move(actions),
-        Milliseconds(dwellTime), thresholdValue, thresholdName, severity));
+        bus->get_io_context(), triggerId, sensors, std::move(actions),
+        Milliseconds(dwellTime), thresholdValue, thresholdName, severity,
+        std::make_unique<Clock>()));
 }
 
 void TriggerFactory::makeNumericThreshold(
     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors,
@@ -183,12 +193,13 @@
                                  bus->get_io_context(), reportIds);
 
     thresholds.emplace_back(std::make_shared<NumericThreshold>(
-        bus->get_io_context(), sensors, std::move(actions), dwellTime,
-        direction, thresholdValue, type));
+        bus->get_io_context(), triggerId, sensors, std::move(actions),
+        dwellTime, direction, thresholdValue, type, std::make_unique<Clock>()));
 }
 
 void TriggerFactory::makeOnChangeThreshold(
     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+    const std::string& triggerId,
     const std::vector<TriggerAction>& triggerActions,
     const std::shared_ptr<std::vector<std::string>>& reportIds,
     const Sensors& sensors) const
@@ -198,12 +209,12 @@
     action::discrete::onChange::fillActions(actions, triggerActions,
                                             bus->get_io_context(), reportIds);
 
-    thresholds.emplace_back(
-        std::make_shared<OnChangeThreshold>(sensors, std::move(actions)));
+    thresholds.emplace_back(std::make_shared<OnChangeThreshold>(
+        triggerId, sensors, std::move(actions), std::make_unique<Clock>()));
 }
 
 std::unique_ptr<interfaces::Trigger> TriggerFactory::make(
-    const std::string& id, const std::string& name,
+    const std::string& idIn, const std::string& name,
     const std::vector<std::string>& triggerActionsIn,
     const std::vector<std::string>& reportIdsIn,
     interfaces::TriggerManager& triggerManager,
@@ -217,15 +228,17 @@
             return toTriggerAction(triggerActionStr);
         });
     std::vector<std::shared_ptr<interfaces::Threshold>> thresholds;
+    auto id = std::make_unique<const std::string>(idIn);
 
     auto reportIds = std::make_shared<std::vector<std::string>>(reportIdsIn);
 
-    updateThresholds(thresholds, triggerActions, reportIds, sensors,
+    updateThresholds(thresholds, *id, triggerActions, reportIds, sensors,
                      labeledThresholdParams);
 
     return std::make_unique<Trigger>(
-        bus->get_io_context(), objServer, id, name, triggerActions, reportIds,
-        std::move(thresholds), triggerManager, triggerStorage, *this, sensors);
+        bus->get_io_context(), objServer, std::move(id), name, triggerActions,
+        reportIds, std::move(thresholds), triggerManager, triggerStorage, *this,
+        sensors);
 }
 
 Sensors TriggerFactory::getSensors(
diff --git a/src/trigger_factory.hpp b/src/trigger_factory.hpp
index 40dfcfd..a2ad568 100644
--- a/src/trigger_factory.hpp
+++ b/src/trigger_factory.hpp
@@ -34,6 +34,7 @@
 
     void updateThresholds(
         std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
@@ -57,6 +58,7 @@
 
     void updateDiscreteThresholds(
         std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
@@ -64,6 +66,7 @@
 
     void updateNumericThresholds(
         std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
@@ -71,6 +74,7 @@
 
     void makeDiscreteThreshold(
         std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
@@ -78,6 +82,7 @@
 
     void makeNumericThreshold(
         std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors,
@@ -85,6 +90,7 @@
 
     void makeOnChangeThreshold(
         std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
+        const std::string& triggerId,
         const std::vector<TriggerAction>& triggerActions,
         const std::shared_ptr<std::vector<std::string>>& reportIds,
         const Sensors& sensors) const;
diff --git a/src/types/trigger_types.hpp b/src/types/trigger_types.hpp
index 778a9a1..4d0b3bd 100644
--- a/src/types/trigger_types.hpp
+++ b/src/types/trigger_types.hpp
@@ -13,8 +13,8 @@
 
 enum class TriggerAction
 {
-    LogToLogService = 0,
-    RedfishEvent,
+    LogToJournal = 0,
+    LogToRedfishEventLog,
     UpdateReport,
 };
 
@@ -22,8 +22,9 @@
 {
 constexpr std::array<std::pair<std::string_view, TriggerAction>, 3>
     convDataTriggerAction = {
-        std::make_pair("LogToLogService", TriggerAction::LogToLogService),
-        std::make_pair("RedfishEvent", TriggerAction::RedfishEvent),
+        std::make_pair("LogToJournal", TriggerAction::LogToJournal),
+        std::make_pair("LogToRedfishEventLog",
+                       TriggerAction::LogToRedfishEventLog),
         std::make_pair("UpdateReport", TriggerAction::UpdateReport)};
 }
 
@@ -160,3 +161,19 @@
     return std::holds_alternative<std::vector<discrete::LabeledThresholdParam>>(
         params);
 }
+
+using TriggerId = std::unique_ptr<const std::string>;
+using TriggerValue = std::variant<double, std::string>;
+using ThresholdName = std::optional<std::reference_wrapper<const std::string>>;
+
+inline std::string triggerValueToString(TriggerValue val)
+{
+    if (auto* doubleVal = std::get_if<double>(&val); doubleVal != nullptr)
+    {
+        return std::to_string(*doubleVal);
+    }
+    else
+    {
+        return std::get<std::string>(val);
+    }
+}
diff --git a/tests/src/mocks/clock_mock.hpp b/tests/src/mocks/clock_mock.hpp
new file mode 100644
index 0000000..2008e7e
--- /dev/null
+++ b/tests/src/mocks/clock_mock.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "interfaces/clock.hpp"
+#include "types/duration_types.hpp"
+
+#include <gmock/gmock.h>
+
+class ClockMock : public interfaces::Clock
+{
+  public:
+    MOCK_METHOD(Milliseconds, steadyTimestamp, (), (const, noexcept, override));
+    MOCK_METHOD(Milliseconds, systemTimestamp, (), (const, noexcept, override));
+};
diff --git a/tests/src/mocks/trigger_action_mock.hpp b/tests/src/mocks/trigger_action_mock.hpp
index 65585d8..cbf5bf3 100644
--- a/tests/src/mocks/trigger_action_mock.hpp
+++ b/tests/src/mocks/trigger_action_mock.hpp
@@ -7,6 +7,8 @@
 class TriggerActionMock : public interfaces::TriggerAction
 {
   public:
-    MOCK_METHOD(void, commit, (const std::string&, Milliseconds, double),
+    MOCK_METHOD(void, commit,
+                (const std::string&, const ThresholdName, const std::string&,
+                 const Milliseconds, const TriggerValue),
                 (override));
 };
diff --git a/tests/src/mocks/trigger_factory_mock.hpp b/tests/src/mocks/trigger_factory_mock.hpp
index 80a62a1..d3d83e5 100644
--- a/tests/src/mocks/trigger_factory_mock.hpp
+++ b/tests/src/mocks/trigger_factory_mock.hpp
@@ -42,6 +42,7 @@
     MOCK_METHOD(void, updateThresholds,
                 (std::vector<std::shared_ptr<interfaces::Threshold>> &
                      currentThresholds,
+                 const std::string& triggerId,
                  const std::vector<TriggerAction>& triggerActions,
                  const std::shared_ptr<std::vector<std::string>>& reportIds,
                  const Sensors& sensors,
diff --git a/tests/src/test_discrete_threshold.cpp b/tests/src/test_discrete_threshold.cpp
index b68d1c3..953ddd5 100644
--- a/tests/src/test_discrete_threshold.cpp
+++ b/tests/src/test_discrete_threshold.cpp
@@ -1,6 +1,7 @@
 #include "dbus_environment.hpp"
 #include "discrete_threshold.hpp"
 #include "helpers.hpp"
+#include "mocks/clock_mock.hpp"
 #include "mocks/sensor_mock.hpp"
 #include "mocks/trigger_action_mock.hpp"
 #include "types/duration_types.hpp"
@@ -22,20 +23,24 @@
         std::make_unique<StrictMock<TriggerActionMock>>();
     TriggerActionMock& actionMock = *actionMockPtr;
     std::shared_ptr<DiscreteThreshold> sut;
+    std::string triggerId = "MyTrigger";
+    std::unique_ptr<NiceMock<ClockMock>> clockMockPtr =
+        std::make_unique<NiceMock<ClockMock>>();
 
     std::shared_ptr<DiscreteThreshold>
         makeThreshold(Milliseconds dwellTime, std::string thresholdValue,
-                      discrete::Severity severity = discrete::Severity::ok)
+                      discrete::Severity severity = discrete::Severity::ok,
+                      std::string thresholdName = "treshold name")
     {
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
         actions.push_back(std::move(actionMockPtr));
 
         return std::make_shared<DiscreteThreshold>(
-            DbusEnvironment::getIoc(),
+            DbusEnvironment::getIoc(), triggerId,
             utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
                 sensorMocks),
-            std::move(actions), dwellTime, thresholdValue, "treshold name",
-            severity);
+            std::move(actions), dwellTime, thresholdValue, thresholdName,
+            severity, std::move(clockMockPtr));
     }
 
     void SetUp() override
@@ -65,7 +70,7 @@
 
 TEST_F(TestDiscreteThreshold, thresholdIsNotInitializeExpectNoActionCommit)
 {
-    EXPECT_CALL(actionMock, commit(_, _, _)).Times(0);
+    EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
 }
 
 class TestDiscreteThresholdValues :
@@ -97,33 +102,55 @@
     EXPECT_THROW(makeThreshold(0ms, GetParam()), std::invalid_argument);
 }
 
+class TestDiscreteThresholdInit : public TestDiscreteThreshold
+{
+    void SetUp() override
+    {}
+};
+
+TEST_F(TestDiscreteThresholdInit, nonEmptyNameIsNotChanged)
+{
+    auto sut = makeThreshold(0ms, "12.3", discrete::Severity::ok, "non-empty");
+    EXPECT_THAT(
+        std::get<discrete::LabeledThresholdParam>(sut->getThresholdParam())
+            .at_label<utils::tstring::UserId>(),
+        Eq("non-empty"));
+}
+
+TEST_F(TestDiscreteThresholdInit, emptyNameIsChanged)
+{
+    auto sut = makeThreshold(0ms, "12.3", discrete::Severity::ok, "");
+    EXPECT_THAT(
+        std::get<discrete::LabeledThresholdParam>(sut->getThresholdParam())
+            .at_label<utils::tstring::UserId>(),
+        Not(Eq("")));
+}
+
 struct DiscreteParams
 {
     struct UpdateParams
     {
         size_t sensor;
-        Milliseconds timestamp;
         double value;
         Milliseconds sleepAfter;
 
-        UpdateParams(size_t sensor, Milliseconds timestamp, double value,
+        UpdateParams(size_t sensor, double value,
                      Milliseconds sleepAfter = 0ms) :
             sensor(sensor),
-            timestamp(timestamp), value(value), sleepAfter(sleepAfter)
+            value(value), sleepAfter(sleepAfter)
         {}
     };
 
     struct ExpectedParams
     {
         size_t sensor;
-        Milliseconds timestamp;
         double value;
         Milliseconds waitMin;
 
-        ExpectedParams(size_t sensor, Milliseconds timestamp, double value,
+        ExpectedParams(size_t sensor, double value,
                        Milliseconds waitMin = 0ms) :
             sensor(sensor),
-            timestamp(timestamp), value(value), waitMin(waitMin)
+            value(value), waitMin(waitMin)
         {}
     };
 
@@ -155,21 +182,19 @@
     {
         *os << "{ DwellTime: " << o.dwellTime.count() << "ms ";
         *os << ", ThresholdValue: " << o.thresholdValue;
-        *os << ", Updates: ";
-        for (const auto& [index, timestamp, value, sleepAfter] : o.updates)
+        *os << ", Updates: [ ";
+        for (const auto& [index, value, sleepAfter] : o.updates)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+            *os << "{ SensorIndex: " << index << ", Value: " << value
                 << ", SleepAfter: " << sleepAfter.count() << "ms }, ";
         }
-        *os << "Expected: ";
-        for (const auto& [index, timestamp, value, waitMin] : o.expected)
+        *os << " ] Expected: [ ";
+        for (const auto& [index, value, waitMin] : o.expected)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
+            *os << "{ SensorIndex: " << index << ", Value: " << value
                 << ", waitMin: " << waitMin.count() << "ms }, ";
         }
-        *os << " }";
+        *os << " ] }";
     }
 
     std::vector<UpdateParams> updates;
@@ -200,11 +225,12 @@
 
         InSequence seq;
 
-        for (const auto& [index, timestamp, value, waitMin] :
-             GetParam().expected)
+        for (const auto& [index, value, waitMin] : GetParam().expected)
         {
             EXPECT_CALL(actionMock,
-                        commit(sensorNames[index], timestamp, value))
+                        commit(triggerId, Optional(StrEq("treshold name")),
+                               sensorNames[index], _,
+                               TriggerValue(GetParam().thresholdValue)))
                 .WillOnce(DoAll(
                     InvokeWithoutArgs([idx = index, &timestamps] {
                         timestamps[idx] =
@@ -215,16 +241,14 @@
 
         auto start = std::chrono::high_resolution_clock::now();
 
-        for (const auto& [index, timestamp, value, sleepAfter] :
-             GetParam().updates)
+        for (const auto& [index, value, sleepAfter] : GetParam().updates)
         {
-            sut->sensorUpdated(*sensorMocks[index], timestamp, value);
+            sut->sensorUpdated(*sensorMocks[index], 42ms, value);
             sleep(sleepAfter);
         }
 
         EXPECT_THAT(DbusEnvironment::waitForFutures("commit"), true);
-        for (const auto& [index, timestamp, value, waitMin] :
-             GetParam().expected)
+        for (const auto& [index, value, waitMin] : GetParam().expected)
         {
             EXPECT_THAT(timestamps[index] - start, Ge(waitMin));
         }
@@ -236,7 +260,6 @@
   public:
     void SetUp() override
     {
-
         for (size_t idx = 0; idx < sensorMocks.size(); idx++)
         {
             ON_CALL(*sensorMocks.at(idx), getName())
@@ -247,26 +270,20 @@
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(_, TestDiscreteThresholdNoDwellTime,
-                         Values(DiscreteParams()
-                                    .ThresholdValue("90.0")
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
-                                    .Expected({}),
-                                DiscreteParams()
-                                    .ThresholdValue("90.0")
-                                    .Updates({{0, 1ms, 80.0},
-                                              {0, 2ms, 90.0},
-                                              {0, 3ms, 80.0},
-                                              {0, 4ms, 90.0}})
-                                    .Expected({{0, 2ms, 90.0}, {0, 4ms, 90.0}}),
-                                DiscreteParams()
-                                    .ThresholdValue("90.0")
-                                    .Updates({{0, 1ms, 90.0},
-                                              {0, 2ms, 99.0},
-                                              {1, 3ms, 100.0},
-                                              {1, 4ms, 90.0}})
-                                    .Expected({{0, 1ms, 90.0},
-                                               {1, 4ms, 90.0}})));
+INSTANTIATE_TEST_SUITE_P(
+    _, TestDiscreteThresholdNoDwellTime,
+    Values(DiscreteParams()
+               .ThresholdValue("90.0")
+               .Updates({{0, 80.0}, {0, 89.0}})
+               .Expected({}),
+           DiscreteParams()
+               .ThresholdValue("90.0")
+               .Updates({{0, 80.0}, {0, 90.0}, {0, 80.0}, {0, 90.0}})
+               .Expected({{0, 90.0}, {0, 90.0}}),
+           DiscreteParams()
+               .ThresholdValue("90.0")
+               .Updates({{0, 90.0}, {0, 99.0}, {1, 100.0}, {1, 90.0}})
+               .Expected({{0, 90.0}, {1, 90.0}})));
 
 TEST_P(TestDiscreteThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
 {
@@ -293,31 +310,31 @@
     Values(DiscreteParams()
                .DwellTime(200ms)
                .ThresholdValue("90.0")
-               .Updates({{0, 1ms, 90.0, 100ms}, {0, 2ms, 91.0}, {0, 3ms, 90.0}})
-               .Expected({{0, 3ms, 90.0, 300ms}}),
+               .Updates({{0, 90.0, 100ms}, {0, 91.0}, {0, 90.0}})
+               .Expected({{0, 90.0, 300ms}}),
            DiscreteParams()
                .DwellTime(100ms)
                .ThresholdValue("90.0")
-               .Updates({{0, 1ms, 90.0, 100ms}})
-               .Expected({{0, 1ms, 90.0, 100ms}}),
+               .Updates({{0, 90.0, 100ms}})
+               .Expected({{0, 90.0, 100ms}}),
            DiscreteParams()
                .DwellTime(1000ms)
                .ThresholdValue("90.0")
-               .Updates({{0, 1ms, 90.0, 700ms},
-                         {0, 1ms, 91.0, 100ms},
-                         {0, 1ms, 90.0, 300ms},
-                         {0, 1ms, 91.0, 100ms}})
+               .Updates({{0, 90.0, 700ms},
+                         {0, 91.0, 100ms},
+                         {0, 90.0, 300ms},
+                         {0, 91.0, 100ms}})
                .Expected({}),
            DiscreteParams()
                .DwellTime(200ms)
                .ThresholdValue("90.0")
-               .Updates({{0, 1ms, 90.0},
-                         {1, 2ms, 89.0, 100ms},
-                         {1, 3ms, 90.0, 100ms},
-                         {1, 4ms, 89.0, 100ms},
-                         {1, 5ms, 90.0, 300ms},
-                         {1, 6ms, 89.0, 100ms}})
-               .Expected({{0, 1ms, 90, 200ms}, {1, 5ms, 90, 500ms}})));
+               .Updates({{0, 90.0},
+                         {1, 89.0, 100ms},
+                         {1, 90.0, 100ms},
+                         {1, 89.0, 100ms},
+                         {1, 90.0, 300ms},
+                         {1, 89.0, 100ms}})
+               .Expected({{0, 90, 200ms}, {1, 90, 500ms}})));
 
 TEST_P(TestDiscreteThresholdWithDwellTime, senorsIsUpdatedMultipleTimes)
 {
diff --git a/tests/src/test_numeric_threshold.cpp b/tests/src/test_numeric_threshold.cpp
index 65c976c..69ad0de 100644
--- a/tests/src/test_numeric_threshold.cpp
+++ b/tests/src/test_numeric_threshold.cpp
@@ -1,5 +1,6 @@
 #include "dbus_environment.hpp"
 #include "helpers.hpp"
+#include "mocks/clock_mock.hpp"
 #include "mocks/sensor_mock.hpp"
 #include "mocks/trigger_action_mock.hpp"
 #include "numeric_threshold.hpp"
@@ -21,6 +22,9 @@
         std::make_unique<StrictMock<TriggerActionMock>>();
     TriggerActionMock& actionMock = *actionMockPtr;
     std::shared_ptr<NumericThreshold> sut;
+    std::string triggerId = "MyTrigger";
+    std::unique_ptr<NiceMock<ClockMock>> clockMockPtr =
+        std::make_unique<NiceMock<ClockMock>>();
 
     void makeThreshold(Milliseconds dwellTime, numeric::Direction direction,
                        double thresholdValue,
@@ -30,10 +34,11 @@
         actions.push_back(std::move(actionMockPtr));
 
         sut = std::make_shared<NumericThreshold>(
-            DbusEnvironment::getIoc(),
+            DbusEnvironment::getIoc(), triggerId,
             utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
                 sensorMocks),
-            std::move(actions), dwellTime, direction, thresholdValue, type);
+            std::move(actions), dwellTime, direction, thresholdValue, type,
+            std::move(clockMockPtr));
     }
 
     void SetUp() override
@@ -64,7 +69,7 @@
 
 TEST_F(TestNumericThreshold, thresholdIsNotInitializeExpectNoActionCommit)
 {
-    EXPECT_CALL(actionMock, commit(_, _, _)).Times(0);
+    EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
 }
 
 TEST_F(TestNumericThreshold, getLabeledParamsReturnsCorrectly)
@@ -76,56 +81,167 @@
 
 struct NumericParams
 {
+    struct UpdateParams
+    {
+        size_t sensor;
+        double value;
+        Milliseconds sleepAfter;
+
+        UpdateParams(size_t sensor, double value,
+                     Milliseconds sleepAfter = 0ms) :
+            sensor(sensor),
+            value(value), sleepAfter(sleepAfter)
+        {}
+    };
+
+    struct ExpectedParams
+    {
+        size_t sensor;
+        double value;
+        Milliseconds waitMin;
+
+        ExpectedParams(size_t sensor, double value,
+                       Milliseconds waitMin = 0ms) :
+            sensor(sensor),
+            value(value), waitMin(waitMin)
+        {}
+    };
+
     NumericParams& Direction(numeric::Direction val)
     {
         direction = val;
         return *this;
     }
 
-    NumericParams&
-        Updates(std::vector<std::tuple<size_t, Milliseconds, double>> val)
+    NumericParams& Updates(std::vector<UpdateParams> val)
     {
         updates = std::move(val);
         return *this;
     }
 
-    NumericParams&
-        Expected(std::vector<std::tuple<size_t, Milliseconds, double>> val)
+    NumericParams& Expected(std::vector<ExpectedParams> val)
     {
         expected = std::move(val);
         return *this;
     }
 
+    NumericParams& ThresholdValue(double val)
+    {
+        thresholdValue = val;
+        return *this;
+    }
+
+    NumericParams& DwellTime(Milliseconds val)
+    {
+        dwellTime = std::move(val);
+        return *this;
+    }
+
+    NumericParams& InitialValues(std::vector<double> val)
+    {
+        initialValues = std::move(val);
+        return *this;
+    }
+
     friend void PrintTo(const NumericParams& o, std::ostream* os)
     {
-        *os << "{ Direction: " << static_cast<int>(o.direction)
-            << ", Updates: ";
-        for (const auto& [index, timestamp, value] : o.updates)
+        *os << "{ DwellTime: " << o.dwellTime.count() << "ms ";
+        *os << ", ThresholdValue: " << o.thresholdValue;
+        *os << ", Direction: " << static_cast<int>(o.direction);
+        *os << ", InitialValues: [ ";
+        size_t idx = 0;
+        for (const double value : o.initialValues)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
-                << " }, ";
+            *os << "{ SensorIndex: " << idx << ", Value: " << value << " }, ";
+            idx++;
         }
-        *os << "Expected: ";
-        for (const auto& [index, timestamp, value] : o.expected)
+        *os << " ], Updates: [ ";
+        for (const auto& [index, value, sleepAfter] : o.updates)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
-                << " }, ";
+            *os << "{ SensorIndex: " << index << ", Value: " << value
+                << ", SleepAfter: " << sleepAfter.count() << "ms }, ";
         }
-        *os << " }";
+        *os << " ], Expected: [ ";
+        for (const auto& [index, value, waitMin] : o.expected)
+        {
+            *os << "{ SensorIndex: " << index << ", Value: " << value
+                << ", waitMin: " << waitMin.count() << "ms }, ";
+        }
+        *os << " ] }";
     }
 
     numeric::Direction direction;
-    std::vector<std::tuple<size_t, Milliseconds, double>> updates;
-    std::vector<std::tuple<size_t, Milliseconds, double>> expected;
+    double thresholdValue = 0.0;
+    Milliseconds dwellTime = 0ms;
+    std::vector<UpdateParams> updates;
+    std::vector<ExpectedParams> expected;
+    std::vector<double> initialValues;
 };
 
-class TestNumericThresholdNoDwellTime :
+class TestNumericThresholdCommon :
     public TestNumericThreshold,
     public WithParamInterface<NumericParams>
 {
   public:
+    void sleep(Milliseconds duration)
+    {
+        if (duration != 0ms)
+        {
+            DbusEnvironment::sleepFor(duration);
+        }
+    }
+
+    void testBodySensorIsUpdatedMultipleTimes()
+    {
+        std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>
+            timestamps(sensorMocks.size());
+
+        sut->initialize();
+
+        InSequence seq;
+
+        for (const auto& [index, value, waitMin] : GetParam().expected)
+        {
+            EXPECT_CALL(actionMock,
+                        commit(triggerId, Eq(std::nullopt), sensorNames[index],
+                               _, TriggerValue(value)))
+                .WillOnce(DoAll(
+                    InvokeWithoutArgs([idx = index, &timestamps] {
+                        timestamps[idx] =
+                            std::chrono::high_resolution_clock::now();
+                    }),
+                    InvokeWithoutArgs(DbusEnvironment::setPromise("commit"))));
+        }
+
+        auto start = std::chrono::high_resolution_clock::now();
+
+        size_t idx = 0;
+        for (const double value : GetParam().initialValues)
+        {
+            sut->sensorUpdated(*sensorMocks[idx], 0ms, value);
+            idx++;
+        }
+
+        for (const auto& [index, value, sleepAfter] : GetParam().updates)
+        {
+            ASSERT_LT(index, GetParam().initialValues.size())
+                << "Initial value was not specified for sensor with index: "
+                << index;
+            sut->sensorUpdated(*sensorMocks[index], 42ms, value);
+            sleep(sleepAfter);
+        }
+
+        EXPECT_THAT(DbusEnvironment::waitForFutures("commit"), true);
+        for (const auto& [index, value, waitMin] : GetParam().expected)
+        {
+            EXPECT_THAT(timestamps[index] - start, Ge(waitMin));
+        }
+    }
+};
+
+class TestNumericThresholdNoDwellTime : public TestNumericThresholdCommon
+{
+  public:
     void SetUp() override
     {
         for (size_t idx = 0; idx < sensorMocks.size(); idx++)
@@ -134,93 +250,84 @@
                 .WillByDefault(Return(sensorNames[idx]));
         }
 
-        makeThreshold(0ms, GetParam().direction, 90.0);
+        makeThreshold(0ms, GetParam().direction, GetParam().thresholdValue);
     }
 };
 
 INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdNoDwellTime,
                          Values(NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
+                                    .InitialValues({80.0})
+                                    .Updates({{0, 89.0}})
                                     .Expected({}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
-                                    .Expected({{0, 2ms, 91.0}}),
+                                    .InitialValues({80.0})
+                                    .Updates({{0, 91.0}})
+                                    .Expected({{0, 91.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {0, 2ms, 99.0},
-                                              {0, 3ms, 80.0},
-                                              {0, 4ms, 98.0}})
-                                    .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}),
+                                    .InitialValues({80.0})
+                                    .Updates({{0, 99.0}, {0, 80.0}, {0, 98.0}})
+                                    .Expected({{0, 99.0}, {0, 98.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {0, 2ms, 99.0},
-                                              {1, 3ms, 100.0},
-                                              {1, 4ms, 98.0}})
-                                    .Expected({{0, 2ms, 99.0}}),
+                                    .InitialValues({80.0, 100.0})
+                                    .Updates({{0, 99.0}, {1, 98.0}})
+                                    .Expected({{0, 99.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
+                                    .InitialValues({100.0})
+                                    .Updates({{0, 91.0}})
                                     .Expected({}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
-                                    .Expected({{0, 2ms, 80.0}}),
+                                    .InitialValues({100.0})
+                                    .Updates({{0, 80.0}})
+                                    .Expected({{0, 80.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 99.0},
-                                              {0, 4ms, 85.0}})
-                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}),
+                                    .InitialValues({100.0})
+                                    .Updates({{0, 80.0}, {0, 99.0}, {0, 85.0}})
+                                    .Expected({{0, 80.0}, {0, 85.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {1, 3ms, 99.0},
-                                              {1, 4ms, 88.0}})
-                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
+                                    .InitialValues({100.0, 99.0})
+                                    .Updates({{0, 80.0}, {1, 88.0}})
+                                    .Expected({{0, 80.0}, {1, 88.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
+                                    .InitialValues({98.0})
+                                    .Updates({{0, 91.0}})
                                     .Expected({}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {0, 4ms, 91.0}})
-                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}),
+                                    .InitialValues({100.0})
+                                    .Updates({{0, 80.0}, {0, 85.0}, {0, 91.0}})
+                                    .Expected({{0, 80.0}, {0, 91.0}}),
                                 NumericParams()
+                                    .ThresholdValue(90.0)
                                     .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {1, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {1, 4ms, 91.0}})
-                                    .Expected({{0, 3ms, 85.0},
-                                               {1, 4ms, 91.0}})));
+                                    .InitialValues({100.0, 80.0})
+                                    .Updates({{0, 85.0}, {1, 91.0}})
+                                    .Expected({{0, 85.0}, {1, 91.0}})));
 
 TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
 {
-    InSequence seq;
-    for (const auto& [index, timestamp, value] : GetParam().expected)
-    {
-        EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value));
-    }
-
-    sut->initialize();
-    for (const auto& [index, timestamp, value] : GetParam().updates)
-    {
-        sut->sensorUpdated(*sensorMocks[index], timestamp, value);
-    }
+    testBodySensorIsUpdatedMultipleTimes();
 }
 
-class TestNumericThresholdWithDwellTime :
-    public TestNumericThreshold,
-    public WithParamInterface<NumericParams>
+class TestNumericThresholdWithDwellTime : public TestNumericThresholdCommon
 {
   public:
     void SetUp() override
@@ -231,197 +338,172 @@
                 .WillByDefault(Return(sensorNames[idx]));
         }
 
-        makeThreshold(2ms, GetParam().direction, 90.0);
-    }
-
-    void sleep()
-    {
-        DbusEnvironment::sleepFor(4ms);
+        makeThreshold(GetParam().dwellTime, GetParam().direction,
+                      GetParam().thresholdValue);
     }
 };
 
-INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime,
-                         Values(NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
-                                    .Expected({{0, 2ms, 91.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {0, 2ms, 99.0},
-                                              {0, 3ms, 80.0},
-                                              {0, 4ms, 98.0}})
-                                    .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {1, 2ms, 99.0},
-                                              {0, 3ms, 100.0},
-                                              {1, 4ms, 86.0}})
-                                    .Expected({{0, 3ms, 100.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
-                                    .Expected({{0, 2ms, 80.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 99.0},
-                                              {0, 4ms, 85.0}})
-                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {1, 3ms, 99.0},
-                                              {1, 4ms, 88.0}})
-                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {0, 4ms, 91.0}})
-                                    .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {1, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {1, 4ms, 91.0}})
-                                    .Expected({{0, 3ms, 85.0},
-                                               {1, 4ms, 91.0}})));
+INSTANTIATE_TEST_SUITE_P(
+    SleepAfterEveryUpdate, TestNumericThresholdWithDwellTime,
+    Values(NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 89.0, 200ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 91.0, 200ms}})
+               .Expected({{0, 91.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 99.0, 200ms}, {0, 80.0, 100ms}, {0, 98.0, 200ms}})
+               .Expected({{0, 99.0, 200ms}, {0, 98.0, 500ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0, 99.0})
+               .Updates({{0, 100.0, 100ms}, {1, 86.0, 100ms}})
+               .Expected({{0, 100.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 91.0, 200ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0, 200ms}})
+               .Expected({{0, 80.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0, 200ms}, {0, 99.0, 100ms}, {0, 85.0, 200ms}})
+               .Expected({{0, 80.0, 200ms}, {0, 85.0, 500ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0, 99.0})
+               .Updates({{0, 80.0, 200ms}, {1, 88.0, 200ms}})
+               .Expected({{0, 80.0, 200ms}, {1, 88.0, 400ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({98.0})
+               .Updates({{0, 91.0, 200ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0, 100ms}, {0, 85.0, 100ms}, {0, 91.0, 200ms}})
+               .Expected({{0, 80.0, 200ms}, {0, 91.0, 400ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({100.0, 80.0})
+               .Updates({{0, 85.0, 100ms}, {1, 91.0, 200ms}})
+               .Expected({{0, 85.0, 200ms}, {1, 91.0, 300ms}})));
 
-TEST_P(TestNumericThresholdWithDwellTime,
-       senorsIsUpdatedMultipleTimesSleepAfterEveryUpdate)
+INSTANTIATE_TEST_SUITE_P(
+    SleepAfterLastUpdate, TestNumericThresholdWithDwellTime,
+    Values(NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 89.0, 300ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 91.0, 300ms}})
+               .Expected({{0, 91.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0})
+               .Updates({{0, 99.0}, {0, 80.0}, {0, 98.0, 300ms}})
+               .Expected({{0, 98.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::increasing)
+               .InitialValues({80.0, 99.0})
+               .Updates({{0, 100.0}, {1, 98.0, 300ms}})
+               .Expected({{0, 100.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 91.0, 300ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0, 300ms}})
+               .Expected({{0, 80.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0}, {0, 99.0}, {0, 85.0, 300ms}})
+               .Expected({{0, 85.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::decreasing)
+               .InitialValues({100.0, 99.0})
+               .Updates({{0, 80.0}, {1, 88.0, 300ms}})
+               .Expected({{0, 80.0, 200ms}, {1, 88.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({98.0})
+               .Updates({{0, 91.0, 300ms}})
+               .Expected({}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({100.0})
+               .Updates({{0, 80.0}, {0, 85.0}, {0, 91.0, 300ms}})
+               .Expected({{0, 91.0, 200ms}}),
+           NumericParams()
+               .DwellTime(200ms)
+               .ThresholdValue(90.0)
+               .Direction(numeric::Direction::either)
+               .InitialValues({100.0, 80.0})
+               .Updates({{0, 85.0}, {1, 91.0, 300ms}})
+               .Expected({{0, 85.0, 200ms}, {1, 91.0, 200ms}})));
+
+TEST_P(TestNumericThresholdWithDwellTime, senorsIsUpdatedMultipleTimes)
 {
-    InSequence seq;
-    for (const auto& [index, timestamp, value] : GetParam().expected)
-    {
-        EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value));
-    }
-
-    sut->initialize();
-    for (const auto& [index, timestamp, value] : GetParam().updates)
-    {
-        sut->sensorUpdated(*sensorMocks[index], timestamp, value);
-        sleep();
-    }
-}
-
-class TestNumericThresholdWithDwellTime2 :
-    public TestNumericThreshold,
-    public WithParamInterface<NumericParams>
-{
-  public:
-    void SetUp() override
-    {
-        for (size_t idx = 0; idx < sensorMocks.size(); idx++)
-        {
-            ON_CALL(*sensorMocks.at(idx), getName())
-                .WillByDefault(Return(sensorNames[idx]));
-        }
-
-        makeThreshold(2ms, GetParam().direction, 90.0);
-    }
-
-    void sleep()
-    {
-        DbusEnvironment::sleepFor(4ms);
-    }
-};
-
-INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime2,
-                         Values(NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}})
-                                    .Expected({{0, 2ms, 91.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {0, 2ms, 99.0},
-                                              {0, 3ms, 80.0},
-                                              {0, 4ms, 98.0}})
-                                    .Expected({{0, 4ms, 98.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::increasing)
-                                    .Updates({{0, 1ms, 80.0},
-                                              {1, 2ms, 99.0},
-                                              {0, 3ms, 100.0},
-                                              {1, 4ms, 98.0}})
-                                    .Expected({{0, 3ms, 100.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}})
-                                    .Expected({{0, 2ms, 80.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 99.0},
-                                              {0, 4ms, 85.0}})
-                                    .Expected({{0, 4ms, 85.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::decreasing)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {1, 3ms, 99.0},
-                                              {1, 4ms, 88.0}})
-                                    .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}})
-                                    .Expected({}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {0, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {0, 4ms, 91.0}})
-                                    .Expected({{0, 4ms, 91.0}}),
-                                NumericParams()
-                                    .Direction(numeric::Direction::either)
-                                    .Updates({{0, 1ms, 100.0},
-                                              {1, 2ms, 80.0},
-                                              {0, 3ms, 85.0},
-                                              {1, 4ms, 91.0}})
-                                    .Expected({{0, 3ms, 85.0},
-                                               {1, 4ms, 91.0}})));
-
-TEST_P(TestNumericThresholdWithDwellTime2,
-       senorsIsUpdatedMultipleTimesSleepAfterLastUpdate)
-{
-    InSequence seq;
-    for (const auto& [index, timestamp, value] : GetParam().expected)
-    {
-        EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value));
-    }
-
-    sut->initialize();
-    for (const auto& [index, timestamp, value] : GetParam().updates)
-    {
-        sut->sensorUpdated(*sensorMocks[index], timestamp, value);
-    }
-    sleep();
+    testBodySensorIsUpdatedMultipleTimes();
 }
diff --git a/tests/src/test_on_change_threshold.cpp b/tests/src/test_on_change_threshold.cpp
index 60697da..b4a6fd3 100644
--- a/tests/src/test_on_change_threshold.cpp
+++ b/tests/src/test_on_change_threshold.cpp
@@ -1,5 +1,6 @@
 #include "dbus_environment.hpp"
 #include "helpers.hpp"
+#include "mocks/clock_mock.hpp"
 #include "mocks/sensor_mock.hpp"
 #include "mocks/trigger_action_mock.hpp"
 #include "on_change_threshold.hpp"
@@ -21,6 +22,9 @@
         std::make_unique<StrictMock<TriggerActionMock>>();
     TriggerActionMock& actionMock = *actionMockPtr;
     std::shared_ptr<OnChangeThreshold> sut;
+    std::string triggerId = "MyTrigger";
+    std::unique_ptr<NiceMock<ClockMock>> clockMockPtr =
+        std::make_unique<NiceMock<ClockMock>>();
 
     void SetUp() override
     {
@@ -34,9 +38,10 @@
         }
 
         sut = std::make_shared<OnChangeThreshold>(
+            triggerId,
             utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
                 sensorMocks),
-            std::move(actions));
+            std::move(actions), std::move(clockMockPtr));
     }
 };
 
@@ -55,7 +60,7 @@
 
 TEST_F(TestOnChangeThreshold, thresholdIsNotInitializeExpectNoActionCommit)
 {
-    EXPECT_CALL(actionMock, commit(_, _, _)).Times(0);
+    EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
 }
 
 TEST_F(TestOnChangeThreshold, getLabeledParamsReturnsCorrectly)
@@ -66,7 +71,7 @@
 
 TEST_F(TestOnChangeThreshold, firstReadingDoesNoActionCommit)
 {
-    EXPECT_CALL(actionMock, commit(_, _, _)).Times(0);
+    EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
 
     sut->initialize();
     sut->sensorUpdated(*sensorMocks.front(), 0ms, 42);
@@ -74,8 +79,8 @@
 
 struct OnChangeParams
 {
-    using UpdateParams = std::tuple<size_t, Milliseconds, double>;
-    using ExpectedParams = std::tuple<size_t, Milliseconds, double>;
+    using UpdateParams = std::tuple<size_t, double>;
+    using ExpectedParams = std::tuple<size_t, double>;
 
     OnChangeParams& Updates(std::vector<UpdateParams> val)
     {
@@ -91,21 +96,17 @@
 
     friend void PrintTo(const OnChangeParams& o, std::ostream* os)
     {
-        *os << "{ Updates: ";
-        for (const auto& [index, timestamp, value] : o.updates)
+        *os << "{ Updates: [ ";
+        for (const auto& [index, value] : o.updates)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
-                << " }, ";
+            *os << "{ SensorIndex: " << index << ", Value: " << value << " }, ";
         }
-        *os << "Expected: ";
-        for (const auto& [index, timestamp, value] : o.expected)
+        *os << " ] Expected: [ ";
+        for (const auto& [index, value] : o.expected)
         {
-            *os << "{ SensorIndex: " << index
-                << ", Timestamp: " << timestamp.count() << ", Value: " << value
-                << " }, ";
+            *os << "{ SensorIndex: " << index << ", Value: " << value << " }, ";
         }
-        *os << " }";
+        *os << " ] }";
     }
 
     std::vector<UpdateParams> updates;
@@ -119,33 +120,28 @@
 
 INSTANTIATE_TEST_SUITE_P(
     _, TestOnChangeThresholdUpdates,
-    Values(
-        OnChangeParams().Updates({{0, 1ms, 80.0}}).Expected({{0, 1ms, 80.0}}),
-        OnChangeParams()
-            .Updates({{0, 1ms, 80.0}, {1, 2ms, 81.0}})
-            .Expected({{0, 1ms, 80.0}, {1, 2ms, 81.0}}),
-        OnChangeParams()
-            .Updates({{0, 1ms, 80.0}, {0, 2ms, 90.0}})
-            .Expected({{0, 1ms, 80.0}, {0, 2ms, 90.0}}),
-        OnChangeParams()
-            .Updates({{0, 1ms, 80.0}, {1, 2ms, 90.0}, {0, 3ms, 90.0}})
-            .Expected({{0, 1ms, 80.0}, {1, 2ms, 90.0}, {0, 3ms, 90.0}}),
-        OnChangeParams()
-            .Updates({{0, 1ms, 80.0},
-                      {1, 2ms, 80.0},
-                      {1, 3ms, 90.0},
-                      {0, 4ms, 90.0}})
-            .Expected({{0, 1ms, 80.0},
-                       {1, 2ms, 80.0},
-                       {1, 3ms, 90.0},
-                       {0, 4ms, 90.0}})));
+    Values(OnChangeParams().Updates({{0, 80.0}}).Expected({{0, 80.0}}),
+           OnChangeParams()
+               .Updates({{0, 80.0}, {1, 81.0}})
+               .Expected({{0, 80.0}, {1, 81.0}}),
+           OnChangeParams()
+               .Updates({{0, 80.0}, {0, 90.0}})
+               .Expected({{0, 80.0}, {0, 90.0}}),
+           OnChangeParams()
+               .Updates({{0, 80.0}, {1, 90.0}, {0, 90.0}})
+               .Expected({{0, 80.0}, {1, 90.0}, {0, 90.0}}),
+           OnChangeParams()
+               .Updates({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}})
+               .Expected({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}})));
 
 TEST_P(TestOnChangeThresholdUpdates, senorsIsUpdatedMultipleTimes)
 {
     InSequence seq;
-    for (const auto& [index, timestamp, value] : GetParam().expected)
+    for (const auto& [index, value] : GetParam().expected)
     {
-        EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value));
+        EXPECT_CALL(actionMock,
+                    commit(triggerId, Eq(std::nullopt), sensorNames[index], _,
+                           TriggerValue(value)));
     }
 
     sut->initialize();
@@ -153,8 +149,8 @@
     // First reading will be skipped
     sut->sensorUpdated(*sensorMocks.front(), 0ms, 42);
 
-    for (const auto& [index, timestamp, value] : GetParam().updates)
+    for (const auto& [index, value] : GetParam().updates)
     {
-        sut->sensorUpdated(*sensorMocks[index], timestamp, value);
+        sut->sensorUpdated(*sensorMocks[index], 42ms, value);
     }
 }
diff --git a/tests/src/test_trigger.cpp b/tests/src/test_trigger.cpp
index cfb08e9..9032d05 100644
--- a/tests/src/test_trigger.cpp
+++ b/tests/src/test_trigger.cpp
@@ -21,7 +21,7 @@
 using namespace testing;
 using namespace std::literals::string_literals;
 
-static constexpr size_t expectedTriggerVersion = 1;
+static constexpr size_t expectedTriggerVersion = 2;
 
 class TestTrigger : public Test
 {
@@ -78,9 +78,11 @@
         thresholdMocks =
             ThresholdMock::makeThresholds(params.thresholdParams());
 
+        auto id = std::make_unique<const std::string>(params.id());
+
         return std::make_unique<Trigger>(
             DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
-            params.id(), params.name(), params.triggerActions(),
+            std::move(id), params.name(), params.triggerActions(),
             std::make_shared<std::vector<std::string>>(
                 params.reportIds().begin(), params.reportIds().end()),
             std::vector<std::shared_ptr<interfaces::Threshold>>(thresholdMocks),
@@ -224,7 +226,7 @@
 
 TEST_F(TestTrigger, setPropertyThresholds)
 {
-    EXPECT_CALL(*triggerFactoryMockPtr, updateThresholds(_, _, _, _, _));
+    EXPECT_CALL(*triggerFactoryMockPtr, updateThresholds(_, _, _, _, _, _));
     TriggerThresholdParams newThresholds =
         std::vector<discrete::ThresholdParam>(
             {std::make_tuple("discrete threshold", "OK", 10, "12.3")});
diff --git a/tests/src/test_trigger_actions.cpp b/tests/src/test_trigger_actions.cpp
index 911197f..e8c48d4 100644
--- a/tests/src/test_trigger_actions.cpp
+++ b/tests/src/test_trigger_actions.cpp
@@ -31,26 +31,36 @@
         std::make_tuple(static_cast<::numeric::Type>(123), 123.0, 90));
 }
 
-class TestLogToJournalNumeric : public Test, public WithParamInterface<LogParam>
+template <typename ActionType>
+class TestActionNumeric : public Test, public WithParamInterface<LogParam>
 {
   public:
     void SetUp() override
     {
         auto [type, threshold, value] = GetParam();
-        sut = std::make_unique<numeric::LogToJournal>(type, threshold);
+        sut = std::make_unique<ActionType>(type, threshold);
         commmitValue = value;
     }
 
-    std::unique_ptr<numeric::LogToJournal> sut;
+    void commit()
+    {
+        sut->commit("MyTrigger", std::nullopt, "MySensor",
+                    Milliseconds{100'000}, commmitValue);
+    }
+
+    std::unique_ptr<ActionType> sut;
     double commmitValue;
 };
 
+class TestLogToJournalNumeric : public TestActionNumeric<LogToJournal>
+{};
+
 INSTANTIATE_TEST_SUITE_P(LogToJournalNumericParams, TestLogToJournalNumeric,
                          getCorrectParams());
 
 TEST_P(TestLogToJournalNumeric, commitAnActionDoesNotThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue));
+    EXPECT_NO_THROW(commit());
 }
 
 class TestLogToJournalNumericThrow : public TestLogToJournalNumeric
@@ -60,80 +70,91 @@
 
 TEST_P(TestLogToJournalNumericThrow, commitAnActionExpectThrow)
 {
-    EXPECT_ANY_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue));
+    EXPECT_ANY_THROW(commit());
 }
 
-class TestLogToRedfishNumeric : public Test, public WithParamInterface<LogParam>
-{
-  public:
-    void SetUp() override
-    {
-        auto [type, threshold, value] = GetParam();
-        sut = std::make_unique<LogToRedfish>(type, threshold);
-        commmitValue = value;
-    }
-
-    std::unique_ptr<LogToRedfish> sut;
-    double commmitValue;
-};
-
-INSTANTIATE_TEST_SUITE_P(LogToRedfishNumericParams, TestLogToRedfishNumeric,
-                         getCorrectParams());
-
-TEST_P(TestLogToRedfishNumeric, commitExpectNoThrow)
-{
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue));
-}
-
-class TestLogToRedfishNumericThrow : public TestLogToRedfishNumeric
+class TestLogToRedfishEventLogNumeric :
+    public TestActionNumeric<LogToRedfishEventLog>
 {};
 
-INSTANTIATE_TEST_SUITE_P(_, TestLogToRedfishNumericThrow, getIncorrectParams());
+INSTANTIATE_TEST_SUITE_P(LogToRedfishEventLogNumericParams,
+                         TestLogToRedfishEventLogNumeric, getCorrectParams());
 
-TEST_P(TestLogToRedfishNumericThrow, commitExpectToThrow)
+TEST_P(TestLogToRedfishEventLogNumeric, commitExpectNoThrow)
 {
-    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, commmitValue),
-                 std::runtime_error);
+    EXPECT_NO_THROW(commit());
+}
+
+class TestLogToRedfishEventLogNumericThrow :
+    public TestLogToRedfishEventLogNumeric
+{};
+
+INSTANTIATE_TEST_SUITE_P(_, TestLogToRedfishEventLogNumericThrow,
+                         getIncorrectParams());
+
+TEST_P(TestLogToRedfishEventLogNumericThrow, commitExpectToThrow)
+{
+    EXPECT_ANY_THROW(commit());
 }
 
 } // namespace numeric
 
 namespace discrete
 {
-using LogParam = ::discrete::Severity;
+using LogParam = std::tuple<::discrete::Severity, TriggerValue>;
 
 static auto getCorrectParams()
 {
-    return Values(::discrete::Severity::critical, ::discrete::Severity::warning,
-                  ::discrete::Severity::ok);
+    return Values(
+        std::make_tuple(::discrete::Severity::critical,
+                        TriggerValue("DiscreteVal")),
+        std::make_tuple(::discrete::Severity::warning, TriggerValue("On")),
+        std::make_tuple(::discrete::Severity::ok, TriggerValue("Off")));
 }
 
 static auto getIncorrectParams()
 {
-    return Values(static_cast<::discrete::Severity>(-1),
-                  static_cast<::discrete::Severity>(42));
+    return Values(
+        std::make_tuple(static_cast<::discrete::Severity>(-1),
+                        TriggerValue("DiscreteVal42")),
+        std::make_tuple(static_cast<::discrete::Severity>(42),
+                        TriggerValue("On")),
+        std::make_tuple(::discrete::Severity::critical, TriggerValue(42.0)),
+        std::make_tuple(::discrete::Severity::warning, TriggerValue(0.0)),
+        std::make_tuple(::discrete::Severity::ok, TriggerValue(0.1)));
 }
 
-class TestLogToJournalDiscrete :
-    public Test,
-    public WithParamInterface<LogParam>
+template <typename ActionType>
+class TestActionDiscrete : public Test, public WithParamInterface<LogParam>
 {
   public:
     void SetUp() override
     {
-        auto severity = GetParam();
-        sut = std::make_unique<LogToJournal>(severity);
+        auto [severity, value] = GetParam();
+        sut = std::make_unique<ActionType>(severity);
+        commitValue = value;
     }
 
-    std::unique_ptr<LogToJournal> sut;
+    void commit()
+    {
+        std::string thresholdName = "MyThreshold";
+        sut->commit("MyTrigger", std::cref(thresholdName), "MySensor",
+                    Milliseconds{100'000}, commitValue);
+    }
+
+    TriggerValue commitValue;
+    std::unique_ptr<ActionType> sut;
 };
 
+class TestLogToJournalDiscrete : public TestActionDiscrete<LogToJournal>
+{};
+
 INSTANTIATE_TEST_SUITE_P(LogToJournalDiscreteParams, TestLogToJournalDiscrete,
                          getCorrectParams());
 
-TEST_P(TestLogToJournalDiscrete, commitAnActionDoesNotThrow)
+TEST_P(TestLogToJournalDiscrete, commitAnActionWIthDiscreteValueDoesNotThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
+    EXPECT_NO_THROW(commit());
 }
 
 class TestLogToJournalDiscreteThrow : public TestLogToJournalDiscrete
@@ -144,76 +165,83 @@
 
 TEST_P(TestLogToJournalDiscreteThrow, commitAnActionExpectThrow)
 {
-    EXPECT_ANY_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
+    EXPECT_ANY_THROW(commit());
 }
 
-class TestLogToRedfishDiscrete :
-    public Test,
-    public WithParamInterface<LogParam>
-{
-  public:
-    void SetUp() override
-    {
-        auto severity = GetParam();
-        sut = std::make_unique<LogToRedfish>(severity);
-    }
-
-    std::unique_ptr<LogToRedfish> sut;
-};
-
-INSTANTIATE_TEST_SUITE_P(LogToRedfishDiscreteParams, TestLogToRedfishDiscrete,
-                         getCorrectParams());
-
-TEST_P(TestLogToRedfishDiscrete, commitExpectNoThrow)
-{
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
-}
-
-class TestLogToRedfishDiscreteThrow : public TestLogToRedfishDiscrete
+class TestLogToRedfishEventLogDiscrete :
+    public TestActionDiscrete<LogToRedfishEventLog>
 {};
 
-INSTANTIATE_TEST_SUITE_P(_, TestLogToRedfishDiscreteThrow,
+INSTANTIATE_TEST_SUITE_P(LogToRedfishEventLogDiscreteParams,
+                         TestLogToRedfishEventLogDiscrete, getCorrectParams());
+
+TEST_P(TestLogToRedfishEventLogDiscrete, commitExpectNoThrow)
+{
+    EXPECT_NO_THROW(commit());
+}
+
+class TestLogToRedfishEventLogDiscreteThrow :
+    public TestLogToRedfishEventLogDiscrete
+{};
+
+INSTANTIATE_TEST_SUITE_P(_, TestLogToRedfishEventLogDiscreteThrow,
                          getIncorrectParams());
 
-TEST_P(TestLogToRedfishDiscreteThrow, commitExpectToThrow)
+TEST_P(TestLogToRedfishEventLogDiscreteThrow, commitExpectToThrow)
 {
-    EXPECT_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0),
-                 std::runtime_error);
+    EXPECT_ANY_THROW(commit());
 }
 
 namespace onChange
 {
-class TestLogToJournalDiscreteOnChange : public Test
+
+template <typename ActionType>
+class TestActionOnChange : public Test
 {
   public:
     void SetUp() override
     {
-        sut = std::make_unique<LogToJournal>();
+        sut = std::make_unique<ActionType>();
     }
 
-    std::unique_ptr<LogToJournal> sut;
-};
-
-TEST_F(TestLogToJournalDiscreteOnChange, commitExpectNoThrow)
-{
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
-}
-
-class TestLogToRedfishDiscreteOnChange : public Test
-{
-  public:
-    void SetUp() override
+    void commit(TriggerValue value)
     {
-        sut = std::make_unique<LogToRedfish>();
+        sut->commit("MyTrigger", std::nullopt, "MySensor",
+                    Milliseconds{100'000}, value);
     }
 
-    std::unique_ptr<LogToRedfish> sut;
+    std::unique_ptr<ActionType> sut;
 };
 
-TEST_F(TestLogToRedfishDiscreteOnChange, commitExpectNoThrow)
+class TestLogToJournalDiscreteOnChange : public TestActionOnChange<LogToJournal>
+{};
+
+TEST_F(TestLogToJournalDiscreteOnChange, commitNumericValueExpectNoThrow)
 {
-    EXPECT_NO_THROW(sut->commit("Test", Milliseconds{100'000}, 90.0));
+    EXPECT_NO_THROW(commit(90.0));
 }
+
+TEST_F(TestLogToJournalDiscreteOnChange, commitDiscreteValueExpectNoThrow)
+{
+    EXPECT_NO_THROW(commit("Off"));
+}
+
+class TestLogToRedfishEventLogDiscreteOnChange :
+    public TestActionOnChange<LogToRedfishEventLog>
+{};
+
+TEST_F(TestLogToRedfishEventLogDiscreteOnChange,
+       commitNumericValueExpectNoThrow)
+{
+    EXPECT_NO_THROW(commit(90.0));
+}
+
+TEST_F(TestLogToRedfishEventLogDiscreteOnChange,
+       commitDiscreteValueExpectNoThrow)
+{
+    EXPECT_NO_THROW(commit("Off"));
+}
+
 } // namespace onChange
 } // namespace discrete
 
@@ -233,9 +261,16 @@
             std::make_shared<std::vector<std::string>>(std::move(names)));
     }
 
+    void commit(TriggerValue value)
+    {
+        sut->commit(triggerId, std::nullopt, "MySensor", Milliseconds{100'000},
+                    value);
+    }
+
     utils::Messanger messanger;
     NiceMock<MockFunction<void(const messages::UpdateReportInd&)>> updateReport;
     std::unique_ptr<UpdateReport> sut;
+    std::string triggerId = "MyTrigger";
 };
 
 TEST_F(TestUpdateReport, commitWhenReportNameIsEmptyExpectNoReportUpdate)
@@ -243,7 +278,7 @@
     EXPECT_CALL(updateReport, Call(_)).Times(0);
 
     make({});
-    sut->commit("Test", Milliseconds{100'000}, 90.0);
+    commit(90.0);
 }
 
 TEST_F(TestUpdateReport, commitExpectReportUpdate)
@@ -253,7 +288,7 @@
                 Call(FieldsAre(UnorderedElementsAreArray(names))));
 
     make(names);
-    sut->commit("Test", Milliseconds{100'000}, 90.0);
+    commit(90.0);
 }
 
 } // namespace action