xref: /openbmc/phosphor-pid-control/failsafeloggers/failsafe_logger.cpp (revision f8b6e55147148c3cfb42327ff267197a460b411c)
1 #include "failsafe_logger.hpp"
2 
3 #include <chrono>
4 #include <cstdint>
5 #include <iostream>
6 #include <string>
7 
8 namespace pid_control
9 {
10 
outputFailsafeLog(const int64_t zoneId,const bool newFailsafeState,const std::string & location,const std::string & reason)11 void FailsafeLogger::outputFailsafeLog(
12     const int64_t zoneId, const bool newFailsafeState,
13     const std::string& location, const std::string& reason)
14 {
15     // Remove outdated log entries.
16     const auto now = std::chrono::high_resolution_clock::now();
17     uint64_t nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
18                          now.time_since_epoch())
19                          .count();
20     // Limit the log output in 1 second.
21     constexpr uint64_t secondInMS = 1000; // 1 second in milliseconds
22     while (!_logTimestamps.empty() &&
23            nowMs - _logTimestamps.front() >= secondInMS)
24     {
25         _logTimestamps.pop_front();
26     }
27 
28     // There is a failsafe state change, clear the logs in current state.
29     bool originFailsafeState = _currentFailsafeState;
30     if (newFailsafeState != _currentFailsafeState)
31     {
32         _logsInCurrentState.clear();
33         _currentFailsafeState = newFailsafeState;
34     }
35     // Do not output the log if the capacity is reached, or if the log is
36     // already encountered in the current state.
37     std::string locationReason = location + " @ " + reason;
38     if (_logTimestamps.size() >= _logMaxCountPerSecond ||
39         !_logsInCurrentState.contains(locationReason))
40     {
41         return;
42     }
43     _logsInCurrentState.insert(locationReason);
44 
45     // Only output the log if the zone enters, stays in, or leaves failsafe
46     // mode. No need to output the log if the zone stays in non-failsafe mode.
47     if (newFailsafeState)
48     {
49         std::cerr << "Zone `" << zoneId
50                   << "` is in failsafe mode.\t\tWith update at `" << location
51                   << "`: " << reason << "\n";
52     }
53     else if (!newFailsafeState && originFailsafeState)
54     {
55         std::cerr << "Zone `" << zoneId
56                   << "` leaves failsafe mode.\t\tWith update at `" << location
57                   << "`: " << reason << "\n";
58     }
59 
60     _logTimestamps.push_back(nowMs);
61 }
62 
63 } // namespace pid_control
64