| // Copyright 2016 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "power_manager/common/activity_logger.h" |
| |
| #include <cmath> |
| |
| #include <base/format_macros.h> |
| #include <base/logging.h> |
| #include <base/strings/stringprintf.h> |
| |
| #include "power_manager/common/clock.h" |
| |
| namespace power_manager { |
| namespace { |
| |
| // Default LogCallback for BaseActivityLogger. |
| void LogMessage(const std::string& message) { |
| LOG(INFO) << message; |
| } |
| |
| } // namespace |
| |
| void BaseActivityLogger::SetLogCallbackForTest(LogCallback callback) { |
| log_callback_ = callback; |
| } |
| |
| base::TimeDelta BaseActivityLogger::GetStoppedTimerDelayForTest() const { |
| return stopped_timer_.IsRunning() ? stopped_timer_.GetCurrentDelay() |
| : base::TimeDelta(); |
| } |
| |
| base::TimeDelta BaseActivityLogger::GetOngoingTimerDelayForTest() const { |
| return ongoing_timer_.IsRunning() ? ongoing_timer_.GetCurrentDelay() |
| : base::TimeDelta(); |
| } |
| |
| bool BaseActivityLogger::TriggerStoppedTimerForTest() { |
| if (!stopped_timer_.IsRunning()) |
| return false; |
| base::Closure task = stopped_timer_.user_task(); |
| stopped_timer_.Stop(); |
| task.Run(); |
| return true; |
| } |
| |
| bool BaseActivityLogger::TriggerOngoingTimerForTest() { |
| if (!ongoing_timer_.IsRunning()) |
| return false; |
| ongoing_timer_.user_task().Run(); |
| return true; |
| } |
| |
| BaseActivityLogger::BaseActivityLogger(const std::string& activity_name, |
| base::TimeDelta stopped_delay, |
| base::TimeDelta ongoing_interval) |
| : log_callback_(base::Bind(&LogMessage)), |
| clock_(new Clock()), |
| activity_name_(activity_name), |
| stopped_delay_(stopped_delay), |
| ongoing_interval_(ongoing_interval) {} |
| |
| BaseActivityLogger::~BaseActivityLogger() {} |
| |
| std::string BaseActivityLogger::GetDelaySuffix( |
| base::TimeTicks timestamp) const { |
| const base::TimeDelta delay = clock_->GetCurrentTime() - timestamp; |
| return base::StringPrintf("%0.f sec ago", round(delay.InSecondsF())); |
| } |
| |
| PeriodicActivityLogger::PeriodicActivityLogger(const std::string& activity_name, |
| base::TimeDelta stopped_delay, |
| base::TimeDelta ongoing_interval) |
| : BaseActivityLogger(activity_name, stopped_delay, ongoing_interval) { |
| // This class is pointless without a stopped delay -- the caller should just |
| // log every report directly themselves. |
| CHECK(!stopped_delay.is_zero()); |
| // An ongoing interval less than or equal to the stopped delay would result in |
| // the ongoing message being logged constantly. |
| CHECK(ongoing_interval_.is_zero() || ongoing_interval_ > stopped_delay_); |
| } |
| |
| PeriodicActivityLogger::~PeriodicActivityLogger() {} |
| |
| void PeriodicActivityLogger::OnActivityReported() { |
| last_report_time_ = clock_->GetCurrentTime(); |
| |
| // Only log that activity started if we weren't waiting to log that it had |
| // stopped. |
| if (!stopped_timer_.IsRunning()) |
| log_callback_.Run(activity_name_ + " reported"); |
| |
| // Extend the "stopped" timeout and start the "ongoing" timer if it isn't |
| // already running. |
| stopped_timer_.Start(FROM_HERE, stopped_delay_, this, |
| &PeriodicActivityLogger::LogStopped); |
| if (!ongoing_interval_.is_zero() && !ongoing_timer_.IsRunning()) { |
| ongoing_timer_.Start(FROM_HERE, ongoing_interval_, this, |
| &PeriodicActivityLogger::LogOngoing); |
| } |
| } |
| |
| void PeriodicActivityLogger::LogStopped() { |
| log_callback_.Run(activity_name_ + " stopped; last reported " + |
| GetDelaySuffix(last_report_time_)); |
| ongoing_timer_.Stop(); |
| } |
| |
| void PeriodicActivityLogger::LogOngoing() { |
| log_callback_.Run(activity_name_ + " ongoing; last reported " + |
| GetDelaySuffix(last_report_time_)); |
| } |
| |
| StartStopActivityLogger::StartStopActivityLogger( |
| const std::string& activity_name, |
| base::TimeDelta stopped_delay, |
| base::TimeDelta ongoing_interval) |
| : BaseActivityLogger(activity_name, stopped_delay, ongoing_interval) {} |
| |
| StartStopActivityLogger::~StartStopActivityLogger() {} |
| |
| void StartStopActivityLogger::OnActivityStarted() { |
| stopped_time_ = base::TimeTicks(); |
| |
| // Only log that activity started if we weren't waiting to log that it had |
| // stopped. Otherwise, just stop the timer -- it'll be started again when |
| // activity stops. |
| if (!stopped_timer_.IsRunning()) |
| log_callback_.Run(activity_name_ + " started"); |
| else |
| stopped_timer_.Stop(); |
| |
| if (!ongoing_interval_.is_zero() && !ongoing_timer_.IsRunning()) { |
| ongoing_timer_.Start(FROM_HERE, ongoing_interval_, this, |
| &StartStopActivityLogger::LogOngoing); |
| } |
| } |
| |
| void StartStopActivityLogger::OnActivityStopped() { |
| if (stopped_time_ != base::TimeTicks()) { |
| LOG(WARNING) << "Ignoring activity-stopped notification for " |
| << "already-stopped " << activity_name_; |
| return; |
| } |
| |
| stopped_time_ = clock_->GetCurrentTime(); |
| ongoing_timer_.Stop(); |
| |
| if (stopped_delay_.is_zero()) { |
| LogStopped(); |
| } else { |
| stopped_timer_.Start(FROM_HERE, stopped_delay_, this, |
| &StartStopActivityLogger::LogStopped); |
| } |
| } |
| |
| void StartStopActivityLogger::LogStopped() { |
| log_callback_.Run( |
| activity_name_ + " stopped" + |
| (stopped_delay_.is_zero() ? "" : " " + GetDelaySuffix(stopped_time_))); |
| } |
| |
| void StartStopActivityLogger::LogOngoing() { |
| log_callback_.Run(activity_name_ + " ongoing"); |
| } |
| |
| OngoingStateActivityLogger::OngoingStateActivityLogger( |
| base::TimeDelta ongoing_interval) |
| : BaseActivityLogger(std::string(), base::TimeDelta(), ongoing_interval) {} |
| |
| OngoingStateActivityLogger::~OngoingStateActivityLogger() {} |
| |
| void OngoingStateActivityLogger::OnStateChanged(const std::string& state) { |
| state_ = state; |
| if (state_.empty()) { |
| ongoing_timer_.Stop(); |
| } else if (!ongoing_timer_.IsRunning()) { |
| ongoing_timer_.Start(FROM_HERE, ongoing_interval_, this, |
| &OngoingStateActivityLogger::LogOngoing); |
| } |
| } |
| |
| void OngoingStateActivityLogger::LogOngoing() { |
| DCHECK(!state_.empty()); |
| log_callback_.Run(state_); |
| } |
| |
| } // namespace power_manager |