| #include "tlbmc/thermal/failsafe_logger.h" |
| |
| #include <deque> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/log/log.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/str_join.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/time/time.h" |
| #include "tlbmc/thermal/thermal_control_utils.h" |
| |
| namespace milotic_tlbmc { |
| namespace thermal { |
| |
| void FailsafeLoggerCore::OutputFailsafeLog(int zone_id, |
| FailsafeState new_failsafe_state, |
| absl::string_view location, |
| absl::string_view reason) { |
| // Limit the log output in 1 second by removing outdated log entries. |
| absl::Time now = clock_->Now(); |
| absl::MutexLock lock(mutex_); |
| while (!log_time_stamps_.empty() && |
| now - log_time_stamps_.front() >= absl::Seconds(1)) { |
| log_time_stamps_.pop_front(); |
| } |
| |
| // If there is a failsafe state change, clear the logs in current state. |
| FailsafeState origin_failsafe_state = current_failsafe_state_; |
| if (new_failsafe_state != current_failsafe_state_) { |
| current_logs_.clear(); |
| current_failsafe_state_ = new_failsafe_state; |
| } |
| |
| // Do not output the log if the capacity is reached, or if the log is already |
| // encountered in the current state. |
| const std::string location_reason = absl::StrCat(location, "@", reason); |
| if (log_time_stamps_.size() >= max_log_count_per_second_ || |
| current_logs_.contains(location_reason)) { |
| return; |
| } |
| current_logs_.insert(location_reason); |
| |
| // Only output the log if the zone enters, stays in, or leaves failsafe mode. |
| // No need to output the log if the zone stays in non-failsafe mode. |
| if (new_failsafe_state == FailsafeState::Failsafe || |
| origin_failsafe_state == FailsafeState::Failsafe) { |
| absl::string_view mode_change = |
| (new_failsafe_state == FailsafeState::Failsafe) ? "is in" : "leaves"; |
| LOG(WARNING) << absl::StrFormat( |
| "[Thermal Failsafe]: Zone `%d` %s failsafe mode. With update at " |
| "`%s`: %s", |
| zone_id, mode_change, location, reason); |
| log_time_stamps_.push_back(now); |
| } |
| } |
| |
| void FailsafeLogger::LinkSensorToZone(absl::string_view sensor_name, |
| int zone_id) { |
| { |
| absl::MutexLock lock(sensor_name_to_zone_ids_mutex_); |
| sensor_name_to_zone_ids_[sensor_name].push_back(zone_id); |
| } |
| LOG(WARNING) << absl::StrFormat( |
| "[Thermal]: Linked sensor `%s` to a zone `%d`", sensor_name, zone_id); |
| } |
| |
| void FailsafeLogger::LinkSensorToZones(absl::string_view sensor_name, |
| const std::vector<int>& zone_ids) { |
| { |
| absl::MutexLock lock(sensor_name_to_zone_ids_mutex_); |
| sensor_name_to_zone_ids_[sensor_name] = zone_ids; |
| } |
| LOG(WARNING) << absl::StrFormat("[Thermal]: Linked sensor `%s` to zones `%s`", |
| sensor_name, absl::StrJoin(zone_ids, ", ")); |
| } |
| |
| void FailsafeLogger::CreateFailsafeLoggerForZone( |
| int zone_id, FailsafeState current_failsafe_state) { |
| { |
| absl::MutexLock lock(zone_id_to_failsafe_logger_mutex_); |
| zone_id_to_failsafe_logger_[zone_id] = std::make_unique<FailsafeLoggerCore>( |
| max_log_count_per_second_, current_failsafe_state); |
| } |
| LOG(WARNING) << absl::StrFormat( |
| "[Thermal]: Created failsafe logger for zone `%d` with initial failsafe " |
| "state `%s`", |
| zone_id, |
| ((current_failsafe_state == FailsafeState::Failsafe) ? "true" : "false")); |
| } |
| |
| void FailsafeLogger::OutputFailsafeLogFromZone(int zone_id, |
| FailsafeState new_failsafe_state, |
| absl::string_view location, |
| absl::string_view reason) { |
| auto it = zone_id_to_failsafe_logger_.find(zone_id); |
| if (it != zone_id_to_failsafe_logger_.end()) { |
| it->second->OutputFailsafeLog(zone_id, new_failsafe_state, location, |
| reason); |
| } else { |
| LOG(ERROR) << absl::StrFormat( |
| "[Thermal Failsafe]: Failed to output failsafe log for zone `%d` " |
| "because its corresponding failsafe logger is NULL.", |
| zone_id); |
| } |
| } |
| |
| void FailsafeLogger::OutputFailsafeLogFromSensor( |
| absl::string_view sensor_name, FailsafeState new_failsafe_state, |
| absl::string_view location, absl::string_view reason) { |
| for (int zone_id : sensor_name_to_zone_ids_[sensor_name]) { |
| OutputFailsafeLogFromZone(zone_id, new_failsafe_state, location, reason); |
| } |
| } |
| |
| void FailsafeLogger::TryOutputFailsafeLogFromSensor( |
| absl::string_view sensor_name, FailsafeState new_failsafe_state, |
| absl::string_view location, absl::string_view reason, |
| ThreadSafetyMode thread_safety_mode) { |
| if (thread_safety_mode == ThreadSafetyMode::DisableThreadSafety) { |
| OutputFailsafeLogFromSensor(sensor_name, new_failsafe_state, location, |
| reason); |
| return; |
| } |
| absl::MutexLock lock(sensor_name_to_zone_ids_mutex_); |
| OutputFailsafeLogFromSensor(sensor_name, new_failsafe_state, location, |
| reason); |
| } |
| |
| } // namespace thermal |
| } // namespace milotic_tlbmc |