blob: 11adf9ed9a295d1dfba13e7ff6c809b308572eec [file] [log] [blame]
holte68395852017-01-10 20:40:211// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/metrics/metrics_upload_scheduler.h"
6
7#include <stdint.h>
8
holte85bbd9d2017-02-14 20:55:589#include "base/feature_list.h"
10#include "base/metrics/field_trial_params.h"
holte68395852017-01-10 20:40:2111#include "base/metrics/histogram_macros.h"
holte85bbd9d2017-02-14 20:55:5812#include "base/strings/string_number_conversions.h"
holte68395852017-01-10 20:40:2113#include "build/build_config.h"
14#include "components/metrics/metrics_scheduler.h"
15
16namespace metrics {
17
holte85bbd9d2017-02-14 20:55:5818// This feature moves the upload schedule to a seperate schedule from the
19// log rotation schedule. This may change upload timing slightly, but
20// would allow some compartmentalization of uploader logic to allow more
21// code reuse between different metrics services.
22const base::Feature kUploadSchedulerFeature{"UMAUploadScheduler",
23 base::FEATURE_DISABLED_BY_DEFAULT};
holte68395852017-01-10 20:40:2124
holte85bbd9d2017-02-14 20:55:5825namespace {
holte68395852017-01-10 20:40:2126
27// When uploading metrics to the server fails, we progressively wait longer and
28// longer before sending the next log. This backoff process helps reduce load
29// on a server that is having issues.
30// The following is the multiplier we use to expand that inter-log duration.
31const double kBackoffMultiplier = 1.1;
32
33// The maximum backoff interval in minutes.
34const int kMaxBackoffIntervalMinutes = 10;
35
36// Minutes to wait if we are unable to upload due to data usage cap.
37const int kOverDataUsageIntervalMinutes = 5;
38
39// Increases the upload interval each time it's called, to handle the case
40// where the server is having issues.
41base::TimeDelta BackOffUploadInterval(base::TimeDelta interval) {
42 DCHECK_GT(kBackoffMultiplier, 1.0);
43 interval = base::TimeDelta::FromMicroseconds(static_cast<int64_t>(
44 kBackoffMultiplier * interval.InMicroseconds()));
45
46 base::TimeDelta max_interval =
47 base::TimeDelta::FromMinutes(kMaxBackoffIntervalMinutes);
48 if (interval > max_interval || interval.InSeconds() < 0) {
49 interval = max_interval;
50 }
51 return interval;
52}
53
holte85bbd9d2017-02-14 20:55:5854// Gets a time interval in seconds from a variations parameter.
55base::TimeDelta GetTimeParameterSeconds(const std::string& param_name,
56 int default_seconds) {
57 int seconds = base::GetFieldTrialParamByFeatureAsInt(
58 kUploadSchedulerFeature, param_name, default_seconds);
59 return base::TimeDelta::FromSeconds(seconds);
60}
61
62// Time delay after a log is uploaded successfully before attempting another.
63// On mobile, keeping the radio on is very expensive, so prefer to keep this
64// short and send in bursts.
65base::TimeDelta GetUnsentLogsInterval() {
66 return GetTimeParameterSeconds("UnsentLogsIntervalSeconds", 3);
67}
68
69// Inital time delay after a log uploaded fails before retrying it.
70base::TimeDelta GetInitialBackoffInterval() {
71 return GetTimeParameterSeconds("InitialBackoffIntervalSeconds", 15);
72}
73
holte68395852017-01-10 20:40:2174} // namespace
75
76MetricsUploadScheduler::MetricsUploadScheduler(
77 const base::Closure& upload_callback)
78 : MetricsScheduler(upload_callback),
holte85bbd9d2017-02-14 20:55:5879 unsent_logs_interval_(GetUnsentLogsInterval()),
80 initial_backoff_interval_(GetInitialBackoffInterval()),
81 backoff_interval_(initial_backoff_interval_) {}
holte68395852017-01-10 20:40:2182
83MetricsUploadScheduler::~MetricsUploadScheduler() {}
84
85void MetricsUploadScheduler::UploadFinished(bool server_is_healthy) {
86 // If the server is having issues, back off. Otherwise, reset to default
87 // (unless there are more logs to send, in which case the next upload should
88 // happen sooner).
89 if (!server_is_healthy) {
holte85bbd9d2017-02-14 20:55:5890 TaskDone(backoff_interval_);
91 backoff_interval_ = BackOffUploadInterval(backoff_interval_);
holte68395852017-01-10 20:40:2192 } else {
holte85bbd9d2017-02-14 20:55:5893 backoff_interval_ = initial_backoff_interval_;
94 TaskDone(unsent_logs_interval_);
holte68395852017-01-10 20:40:2195 }
holte68395852017-01-10 20:40:2196}
97
holte85bbd9d2017-02-14 20:55:5898void MetricsUploadScheduler::StopAndUploadCancelled() {
99 Stop();
100 TaskDone(unsent_logs_interval_);
holte68395852017-01-10 20:40:21101}
102
103void MetricsUploadScheduler::UploadOverDataUsageCap() {
104 TaskDone(base::TimeDelta::FromMinutes(kOverDataUsageIntervalMinutes));
105}
106
107void MetricsUploadScheduler::LogActualUploadInterval(base::TimeDelta interval) {
108 UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
109 interval.InMinutes(), 1,
110 base::TimeDelta::FromHours(12).InMinutes(), 50);
111}
112
113void MetricsUploadScheduler::TriggerTask() {
114 if (!last_upload_finish_time_.is_null()) {
115 LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
116 last_upload_finish_time_ = base::TimeTicks();
117 }
118 MetricsScheduler::TriggerTask();
119}
120
121} // namespace metrics