blob: 23d63f7d5b0853f0af3dab4d32c9140c8fd21bf9 [file] [log] [blame]
// 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/check.h>
#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;
stopped_timer_.FireNow();
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