blob: ccdca73bf247547f9bb8199b713c856364b9b3fb [file]
#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