Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: components/ukm/ukm_service.cc

Issue 2567263003: Basic UkmService implementation (Closed)
Patch Set: Proto and client_id Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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/ukm/ukm_service.h"
6
7 #include <utility>
8
9 #include "base/feature_list.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/rand_util.h"
14 #include "base/time/time.h"
15 #include "components/metrics/metrics_log_uploader.h"
16 #include "components/metrics/metrics_service_client.h"
17 #include "components/metrics/proto/ukm/report.pb.h"
18 #include "components/prefs/pref_registry_simple.h"
19 #include "components/prefs/pref_service.h"
20 #include "components/ukm/metrics_reporting_scheduler.h"
21 #include "components/ukm/persisted_logs_metrics_impl.h"
22 #include "components/ukm/ukm_pref_names.h"
23 #include "components/variations/variations_associated_data.h"
24
25 namespace ukm {
26
27 namespace {
28
29 const base::Feature kUkmFeature = {
30 "Ukm", base::FEATURE_DISABLED_BY_DEFAULT
31 };
32
33 const char kMimeType[] = "application/vnd.chrome.ukm";
34
35 // Constants for the UKM rollout field trial.
36 const char kUkmRolloutFieldTrialName[] = "UkmRollout";
37
38 // Constant for the finch parameter name for the server URL
rkaplow 2017/01/02 23:23:04 prefer not using finch since it's technically inte
Steven Holte 2017/01/03 21:16:04 Done.
39 const char kUkmRolloutServerUrlParam[] = "ServerUrl";
40
41 // The ukm server's URL.
rkaplow 2017/01/02 23:23:03 UKM
Steven Holte 2017/01/03 21:16:03 Done.
42 const char kDefaultServerUrl[] = "https://clients4.google.com/ukm";
43
44 // The number of UKM logs that must be stored.
rkaplow 2017/01/02 23:23:04 comment
Steven Holte 2017/01/03 21:16:04 Done.
45 const int kInitializationDelaySeconds = 5;
46
47 // The number of UKM logs that must be stored.
rkaplow 2017/01/02 23:23:04 can you comment more on this
Steven Holte 2017/01/03 21:16:04 Done.
48 const int kMinPersistedLogs = 8;
49
50 // The number of bytes UKM logs that must be stored.
rkaplow 2017/01/02 23:23:04 would reword
Steven Holte 2017/01/03 21:16:04 Done.
51 // This ensures that a reasonable amount of history will be stored even if there
52 // is a long series of very small logs.
53 const int kMinPersistedBytes = 300000;
rkaplow 2017/01/02 23:23:04 how did you get this value. I also think it might
Steven Holte 2017/01/03 21:16:04 I've just copied these values from the ones being
54
55 // If an upload fails, and the transmission was over this byte count, then we
56 // will discard the log, and not try to retransmit it. We also don't persist
57 // the log to the prefs for transmission during the next chrome session if this
58 // limit is exceeded.
59 const size_t kUploadLogAvoidRetransmitSize = 100 * 1024;
rkaplow 2017/01/02 23:23:03 i see this is the same name as ni metrics_service
Steven Holte 2017/01/03 21:16:04 Renamed to kMaxLogRetransmitSize
60
61 std::string GetServerUrl() {
62 std::string server_url = variations::GetVariationParamValue(
63 kUkmRolloutFieldTrialName, kUkmRolloutServerUrlParam);
64 if (!server_url.empty())
65 return server_url;
66 else
rkaplow 2017/01/02 23:23:04 nit, would prefer omitting the else
Steven Holte 2017/01/03 21:16:04 Done.
67 return kDefaultServerUrl;
68 }
69
70 uint64_t LoadClientId(PrefService* pref_service) {
rkaplow 2017/01/02 23:23:04 i wonder if this names hides a bit too much logic.
Steven Holte 2017/01/03 21:16:04 Done.
71 uint64_t client_id = pref_service->GetInteger(prefs::kUkmClientId);
72 if (!client_id) {
73 // Generate and store a new client id.
74 client_id = base::RandUint64();
rkaplow 2017/01/02 23:23:04 i know we keep a string GUID for UMA, which ends u
Steven Holte 2017/01/03 21:16:04 GUIDs are actually 128 bits, our current proto onl
75 pref_service->SetInteger(prefs::kUkmClientId, client_id);
76 }
77 return client_id;
78 }
79
80 } // namespace
81
82 UkmService::UkmService(
83 PrefService* pref_service,
84 metrics::MetricsServiceClient* client)
85 : pref_service_(pref_service),
86 client_(client),
87 persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>(
88 new ukm::PersistedLogsMetricsImpl()),
89 pref_service,
90 prefs::kUkmPersistedLogs,
91 NULL,
92 kMinPersistedLogs,
93 kMinPersistedBytes,
94 kUploadLogAvoidRetransmitSize),
95 initialize_started_(false),
96 self_ptr_factory_(this) {
97 DCHECK(pref_service_);
98 DCHECK(client_);
99
100 auto status = persisted_logs_.DeserializeLogs();
101 UMA_HISTOGRAM_ENUMERATION(
102 "Ukm.PersistedLogs.DeserializeLogs.Status",
rkaplow 2017/01/02 23:23:04 UKM
Steven Holte 2017/01/03 21:16:04 Removed this metric, since it's already recorded b
103 status,
104 metrics::PersistedLogs::LogReadStatus::END_RECALL_STATUS);
105
106 base::Closure rotate_callback =
107 base::Bind(&UkmService::RotateLog,
108 self_ptr_factory_.GetWeakPtr());
109 // MetricsServiceClient outlives MetricsService, and
110 // MetricsReportingScheduler is tied to the lifetime of |this|.
111 const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback =
112 base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval,
113 base::Unretained(client_));
114 scheduler_.reset(new ukm::MetricsReportingScheduler(
115 rotate_callback, get_upload_interval_callback));
116 }
117
118 UkmService::~UkmService() {}
119
120 void UkmService::Initialize() {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 DVLOG(1) << "UkmService::Initialize";
123 initialize_started_ = true;
124
125 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
126 FROM_HERE, base::Bind(&UkmService::StartInitTask,
127 self_ptr_factory_.GetWeakPtr()),
128 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
129 }
130
131 void UkmService::EnableReporting() {
132 DCHECK(thread_checker_.CalledOnValidThread());
133 DVLOG(1) << "UkmService::EnableReporting";
134 if (!base::FeatureList::IsEnabled(kUkmFeature))
135 return;
136 if (!initialize_started_)
137 Initialize();
138 scheduler_->Start();
139 }
140
141 void UkmService::DisableReporting() {
142 DCHECK(thread_checker_.CalledOnValidThread());
143 DVLOG(1) << "UkmService::DisableReporting";
144 scheduler_->UploadCancelled();
145 scheduler_->Stop();
146 }
147
148 // static
149 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
150 registry->RegisterIntegerPref(prefs::kUkmClientId, 0);
151 registry->RegisterListPref(prefs::kUkmPersistedLogs);
152 }
153
154 void UkmService::StartInitTask() {
155 DCHECK(thread_checker_.CalledOnValidThread());
156 DVLOG(1) << "UkmService::StartInitTask";
157 client_id_ = LoadClientId(pref_service_);
158 client_->InitializeSystemProfileMetrics(
159 base::Bind(&UkmService::FinishedInitTask,
160 self_ptr_factory_.GetWeakPtr()));
161 }
162
163 void UkmService::FinishedInitTask() {
164 DCHECK(thread_checker_.CalledOnValidThread());
165 DVLOG(1) << "UkmService::FinishedInitTask";
166 scheduler_->InitTaskComplete();
167 }
168
169 void UkmService::RotateLog() {
170 DCHECK(thread_checker_.CalledOnValidThread());
171 DCHECK(!log_upload_in_progress_);
172 DVLOG(1) << "UkmService::RotateLog";
173 if (persisted_logs_.empty()) {
174 BuildAndStoreLog();
175 }
176 StartScheduledUpload();
177 }
178
179 void UkmService::BuildAndStoreLog() {
180 DCHECK(thread_checker_.CalledOnValidThread());
181 DVLOG(1) << "UkmService::BuildAndStoreLog";
182 Report report;
183 report.set_client_id(client_id_);
184 // TODO(holte): Populate system_profile.
185 // TODO(zhenw): Populate sources.
186 std::string serialized_log;
187 report.SerializeToString(&serialized_log);
188 persisted_logs_.StoreLog(serialized_log);
189 }
190
191 void UkmService::StartScheduledUpload() {
192 DCHECK(thread_checker_.CalledOnValidThread());
193 DCHECK(!log_upload_in_progress_);
194 persisted_logs_.StageLog();
rkaplow 2017/01/02 23:23:03 just as a reminder can you add a TODO for various
Steven Holte 2017/01/03 21:16:04 Done.
195 if (!log_uploader_) {
196 log_uploader_ = client_->CreateUploader(
197 GetServerUrl(), kMimeType,
198 base::Bind(&UkmService::OnLogUploadComplete,
199 self_ptr_factory_.GetWeakPtr()));
200 }
201 log_upload_in_progress_ = true;
202 log_uploader_->UploadLog(persisted_logs_.staged_log(),
203 persisted_logs_.staged_log_hash());
204 }
205
206 void UkmService::OnLogUploadComplete(int response_code) {
207 DCHECK(thread_checker_.CalledOnValidThread());
208 DCHECK(log_upload_in_progress_);
209 DVLOG(1) << "UkmService::OnLogUploadComplete";
210 log_upload_in_progress_ = false;
211
212 // Log a histogram to track response success vs. failure rates.
rkaplow 2017/01/02 23:23:04 I'd omit this comment - in the original metrics_se
Steven Holte 2017/01/03 21:16:04 Done.
213 UMA_HISTOGRAM_SPARSE_SLOWLY("UKM.Upload.ResponseCode", response_code);
214
215 bool upload_succeeded = response_code == 200;
216
217 // Provide boolean for error recovery (allow us to ignore response_code).
218 bool discard_log = false;
219 const size_t log_size = persisted_logs_.staged_log().length();
rkaplow 2017/01/02 23:23:04 nit, would add _bytes for clarity
Steven Holte 2017/01/03 21:16:04 Done.
220 if (upload_succeeded) {
221 UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size / 1024);
222 } else if (log_size > kUploadLogAvoidRetransmitSize) {
223 UMA_HISTOGRAM_COUNTS("UKM.OversizeRejected.LogSize",
rkaplow 2017/01/02 23:23:03 prefer UMA_HISTOGRAM_COUNTS_1M
Steven Holte 2017/01/03 21:16:04 Done.
224 static_cast<int>(log_size));
225 discard_log = true;
226 } else if (response_code == 400) {
227 // Bad syntax. Retransmission won't work.
228 discard_log = true;
rkaplow 2017/01/02 23:23:04 should we add a metric to see if this occurs?
Steven Holte 2017/01/03 21:16:04 This should be covered by the ResponseCode histogr
229 }
230
231 if (upload_succeeded || discard_log) {
232 persisted_logs_.DiscardStagedLog();
233 // Store the updated list to disk now that the removed log is uploaded.
234 persisted_logs_.SerializeLogs();
235 }
236
237 // Error 400 indicates a problem with the log, not with the server, so
238 // don't consider that a sign that the server is in trouble.
239 bool server_is_healthy = upload_succeeded || response_code == 400;
240 scheduler_->UploadFinished(server_is_healthy, !persisted_logs_.empty());
241
242 if (server_is_healthy)
243 client_->OnLogUploadComplete();
rkaplow 2017/01/02 23:23:04 I was looking for what this was doing and it seems
Steven Holte 2017/01/03 21:16:04 Done.
244 }
245
246 } // namespace ukm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698