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

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

Issue 2883563002: Refactor UKM interface for mojo-ification (Closed)
Patch Set: Fix uma_session_stats.cc Created 3 years, 7 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
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/ukm/ukm_service.h" 5 #include "components/ukm/ukm_service.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/atomic_sequence_num.h"
12 #include "base/bind.h" 11 #include "base/bind.h"
13 #include "base/feature_list.h" 12 #include "base/feature_list.h"
14 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
15 #include "base/metrics/field_trial.h" 14 #include "base/metrics/field_trial.h"
16 #include "base/metrics/field_trial_params.h" 15 #include "base/metrics/field_trial_params.h"
17 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
18 #include "base/metrics/metrics_hashes.h"
19 #include "base/rand_util.h" 17 #include "base/rand_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_split.h"
22 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/time/time.h" 19 #include "base/time/time.h"
24 #include "components/metrics/metrics_log.h" 20 #include "components/metrics/metrics_log.h"
25 #include "components/metrics/metrics_log_uploader.h"
26 #include "components/metrics/metrics_service_client.h" 21 #include "components/metrics/metrics_service_client.h"
27 #include "components/metrics/proto/ukm/entry.pb.h"
28 #include "components/metrics/proto/ukm/report.pb.h" 22 #include "components/metrics/proto/ukm/report.pb.h"
29 #include "components/metrics/proto/ukm/source.pb.h"
30 #include "components/prefs/pref_registry_simple.h" 23 #include "components/prefs/pref_registry_simple.h"
31 #include "components/prefs/pref_service.h" 24 #include "components/prefs/pref_service.h"
32 #include "components/ukm/persisted_logs_metrics_impl.h" 25 #include "components/ukm/persisted_logs_metrics_impl.h"
33 #include "components/ukm/ukm_entry.h"
34 #include "components/ukm/ukm_entry_builder.h"
35 #include "components/ukm/ukm_pref_names.h" 26 #include "components/ukm/ukm_pref_names.h"
36 #include "components/ukm/ukm_rotation_scheduler.h" 27 #include "components/ukm/ukm_rotation_scheduler.h"
37 #include "components/ukm/ukm_source.h"
38 28
39 namespace ukm { 29 namespace ukm {
40 30
41 namespace { 31 namespace {
42 32
43 // The delay, in seconds, after starting recording before doing expensive 33 // The delay, in seconds, after starting recording before doing expensive
44 // initialization work. 34 // initialization work.
45 constexpr int kInitializationDelaySeconds = 5; 35 constexpr int kInitializationDelaySeconds = 5;
46 36
47 // Gets the list of whitelisted Entries as string. Format is a comma seperated
48 // list of Entry names (as strings).
49 std::string GetWhitelistEntries() {
50 return base::GetFieldTrialParamValueByFeature(kUkmFeature,
51 "WhitelistEntries");
52 }
53
54 // Gets the maximum number of Sources we'll keep in memory before discarding any
55 // new ones being added.
56 size_t GetMaxSources() {
57 constexpr size_t kDefaultMaxSources = 500;
58 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt(
59 kUkmFeature, "MaxSources", kDefaultMaxSources));
60 }
61
62 // Gets the maximum number of Entries we'll keep in memory before discarding any
63 // new ones being added.
64 size_t GetMaxEntries() {
65 constexpr size_t kDefaultMaxEntries = 5000;
66 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt(
67 kUkmFeature, "MaxEntries", kDefaultMaxEntries));
68 }
69
70 // True if we should record the initial_url field of the UKM Source proto.
71 bool ShouldRecordInitialUrl() {
72 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature,
73 "RecordInitialUrl", false);
74 }
75
76 // True if we should record session ids in the UKM Report proto. 37 // True if we should record session ids in the UKM Report proto.
77 bool ShouldRecordSessionId() { 38 bool ShouldRecordSessionId() {
78 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId", 39 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId",
79 false); 40 false);
80 } 41 }
81 42
82 // Generates a new client id and stores it in prefs. 43 // Generates a new client id and stores it in prefs.
83 uint64_t GenerateClientId(PrefService* pref_service) { 44 uint64_t GenerateClientId(PrefService* pref_service) {
84 uint64_t client_id = 0; 45 uint64_t client_id = 0;
85 while (!client_id) 46 while (!client_id)
(...skipping 12 matching lines...) Expand all
98 return client_id; 59 return client_id;
99 } 60 }
100 61
101 int32_t LoadSessionId(PrefService* pref_service) { 62 int32_t LoadSessionId(PrefService* pref_service) {
102 int32_t session_id = pref_service->GetInteger(prefs::kUkmSessionId); 63 int32_t session_id = pref_service->GetInteger(prefs::kUkmSessionId);
103 ++session_id; // increment session id, once per session 64 ++session_id; // increment session id, once per session
104 pref_service->SetInteger(prefs::kUkmSessionId, session_id); 65 pref_service->SetInteger(prefs::kUkmSessionId, session_id);
105 return session_id; 66 return session_id;
106 } 67 }
107 68
108 enum class DroppedDataReason {
109 NOT_DROPPED = 0,
110 RECORDING_DISABLED = 1,
111 MAX_HIT = 2,
112 NOT_WHITELISTED = 3,
113 NUM_DROPPED_DATA_REASONS
114 };
115
116 void RecordDroppedSource(DroppedDataReason reason) {
117 UMA_HISTOGRAM_ENUMERATION(
118 "UKM.Sources.Dropped", static_cast<int>(reason),
119 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS));
120 }
121
122 void RecordDroppedEntry(DroppedDataReason reason) {
123 UMA_HISTOGRAM_ENUMERATION(
124 "UKM.Entries.Dropped", static_cast<int>(reason),
125 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS));
126 }
127
128 } // namespace 69 } // namespace
129 70
130 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT};
131
132 UkmService::UkmService(PrefService* pref_service, 71 UkmService::UkmService(PrefService* pref_service,
133 metrics::MetricsServiceClient* client) 72 metrics::MetricsServiceClient* client)
134 : pref_service_(pref_service), 73 : pref_service_(pref_service),
135 recording_enabled_(false),
136 client_id_(0), 74 client_id_(0),
137 session_id_(0), 75 session_id_(0),
138 client_(client), 76 client_(client),
139 reporting_service_(client, pref_service), 77 reporting_service_(client, pref_service),
140 initialize_started_(false), 78 initialize_started_(false),
141 initialize_complete_(false), 79 initialize_complete_(false),
142 self_ptr_factory_(this) { 80 self_ptr_factory_(this) {
143 DCHECK(pref_service_); 81 DCHECK(pref_service_);
144 DCHECK(client_); 82 DCHECK(client_);
145 DVLOG(1) << "UkmService::Constructor"; 83 DVLOG(1) << "UkmService::Constructor";
(...skipping 25 matching lines...) Expand all
171 DCHECK(!initialize_started_); 109 DCHECK(!initialize_started_);
172 DVLOG(1) << "UkmService::Initialize"; 110 DVLOG(1) << "UkmService::Initialize";
173 initialize_started_ = true; 111 initialize_started_ = true;
174 112
175 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 113 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
176 FROM_HERE, 114 FROM_HERE,
177 base::Bind(&UkmService::StartInitTask, self_ptr_factory_.GetWeakPtr()), 115 base::Bind(&UkmService::StartInitTask, self_ptr_factory_.GetWeakPtr()),
178 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); 116 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
179 } 117 }
180 118
181 void UkmService::EnableRecording() {
182 recording_enabled_ = true;
183 }
184
185 void UkmService::DisableRecording() {
186 recording_enabled_ = false;
187 }
188
189 void UkmService::EnableReporting() { 119 void UkmService::EnableReporting() {
190 DCHECK(thread_checker_.CalledOnValidThread()); 120 DCHECK(thread_checker_.CalledOnValidThread());
191 DVLOG(1) << "UkmService::EnableReporting"; 121 DVLOG(1) << "UkmService::EnableReporting";
192 if (reporting_service_.reporting_active()) 122 if (reporting_service_.reporting_active())
193 return; 123 return;
194 124
195 for (auto& provider : metrics_providers_) 125 for (auto& provider : metrics_providers_)
196 provider->OnRecordingEnabled(); 126 provider->OnRecordingEnabled();
197 127
198 if (!initialize_started_) 128 if (!initialize_started_)
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 DCHECK(thread_checker_.CalledOnValidThread()); 178 DCHECK(thread_checker_.CalledOnValidThread());
249 if (initialize_complete_) 179 if (initialize_complete_)
250 BuildAndStoreLog(); 180 BuildAndStoreLog();
251 reporting_service_.ukm_log_store()->PersistUnsentLogs(); 181 reporting_service_.ukm_log_store()->PersistUnsentLogs();
252 } 182 }
253 183
254 void UkmService::Purge() { 184 void UkmService::Purge() {
255 DCHECK(thread_checker_.CalledOnValidThread()); 185 DCHECK(thread_checker_.CalledOnValidThread());
256 DVLOG(1) << "UkmService::Purge"; 186 DVLOG(1) << "UkmService::Purge";
257 reporting_service_.ukm_log_store()->Purge(); 187 reporting_service_.ukm_log_store()->Purge();
258 sources_.clear(); 188 UkmRecorderImpl::Purge();
259 entries_.clear();
260 } 189 }
261 190
262 // TODO(bmcquade): rename this to something more generic, like 191 // TODO(bmcquade): rename this to something more generic, like
263 // ResetClientState. Consider resetting all prefs here. 192 // ResetClientState. Consider resetting all prefs here.
264 void UkmService::ResetClientId() { 193 void UkmService::ResetClientId() {
265 client_id_ = GenerateClientId(pref_service_); 194 client_id_ = GenerateClientId(pref_service_);
266 session_id_ = LoadSessionId(pref_service_); 195 session_id_ = LoadSessionId(pref_service_);
267 } 196 }
268 197
269 void UkmService::RegisterMetricsProvider( 198 void UkmService::RegisterMetricsProvider(
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 BuildAndStoreLog(); 230 BuildAndStoreLog();
302 reporting_service_.Start(); 231 reporting_service_.Start();
303 } 232 }
304 233
305 void UkmService::BuildAndStoreLog() { 234 void UkmService::BuildAndStoreLog() {
306 DCHECK(thread_checker_.CalledOnValidThread()); 235 DCHECK(thread_checker_.CalledOnValidThread());
307 DVLOG(1) << "UkmService::BuildAndStoreLog"; 236 DVLOG(1) << "UkmService::BuildAndStoreLog";
308 237
309 // Suppress generating a log if we have no new data to include. 238 // Suppress generating a log if we have no new data to include.
310 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot. 239 // TODO(zhenw): add a histogram here to debug if this case is hitting a lot.
311 if (sources_.empty() && entries_.empty()) 240 if (sources().empty() && entries().empty())
312 return; 241 return;
313 242
314 Report report; 243 Report report;
315 report.set_client_id(client_id_); 244 report.set_client_id(client_id_);
316 if (ShouldRecordSessionId()) 245 if (ShouldRecordSessionId())
317 report.set_session_id(session_id_); 246 report.set_session_id(session_id_);
318 247
319 for (const auto& kv : sources_) { 248 StoreRecordingsInReport(&report);
320 Source* proto_source = report.add_sources();
321 kv.second->PopulateProto(proto_source);
322 if (!ShouldRecordInitialUrl())
323 proto_source->clear_initial_url();
324 }
325 for (const auto& entry : entries_) {
326 Entry* proto_entry = report.add_entries();
327 entry->PopulateProto(proto_entry);
328 }
329
330 UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size());
331 UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size());
332 sources_.clear();
333 entries_.clear();
334 249
335 metrics::MetricsLog::RecordCoreSystemProfile(client_, 250 metrics::MetricsLog::RecordCoreSystemProfile(client_,
336 report.mutable_system_profile()); 251 report.mutable_system_profile());
337 252
338 for (auto& provider : metrics_providers_) { 253 for (auto& provider : metrics_providers_) {
339 provider->ProvideSystemProfileMetrics(report.mutable_system_profile()); 254 provider->ProvideSystemProfileMetrics(report.mutable_system_profile());
340 } 255 }
341 256
342 std::string serialized_log; 257 std::string serialized_log;
343 report.SerializeToString(&serialized_log); 258 report.SerializeToString(&serialized_log);
344 reporting_service_.ukm_log_store()->StoreLog(serialized_log); 259 reporting_service_.ukm_log_store()->StoreLog(serialized_log);
345 } 260 }
346 261
347 // static
348 int32_t UkmService::GetNewSourceID() {
349 static base::StaticAtomicSequenceNumber seq;
350 return seq.GetNext();
351 }
352
353 std::unique_ptr<UkmEntryBuilder> UkmService::GetEntryBuilder(
354 int32_t source_id,
355 const char* event_name) {
356 return std::unique_ptr<UkmEntryBuilder>(new UkmEntryBuilder(
357 base::Bind(&UkmService::AddEntry, base::Unretained(this)), source_id,
358 event_name));
359 }
360
361 void UkmService::UpdateSourceURL(int32_t source_id, const GURL& url) {
362 DCHECK(thread_checker_.CalledOnValidThread());
363
364 if (!recording_enabled_) {
365 RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED);
366 return;
367 }
368
369 // Update the pre-existing source if there is any. This happens when the
370 // initial URL is different from the committed URL for the same source, e.g.,
371 // when there is redirection.
372 if (base::ContainsKey(sources_, source_id)) {
373 sources_[source_id]->UpdateUrl(url);
374 return;
375 }
376
377 if (sources_.size() >= GetMaxSources()) {
378 RecordDroppedSource(DroppedDataReason::MAX_HIT);
379 return;
380 }
381 std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>();
382 source->set_id(source_id);
383 source->set_url(url);
384 sources_.insert(std::make_pair(source_id, std::move(source)));
385 }
386
387 void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) {
388 DCHECK(thread_checker_.CalledOnValidThread());
389
390 if (!recording_enabled_) {
391 RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED);
392 return;
393 }
394 if (entries_.size() >= GetMaxEntries()) {
395 RecordDroppedEntry(DroppedDataReason::MAX_HIT);
396 return;
397 }
398
399 if (!whitelisted_entry_hashes_.empty() &&
400 !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash())) {
401 RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED);
402 return;
403 }
404
405 entries_.push_back(std::move(entry));
406 }
407
408 void UkmService::StoreWhitelistedEntries() {
409 const auto entries =
410 base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE,
411 base::SPLIT_WANT_NONEMPTY);
412 for (const auto& entry_string : entries) {
413 whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string));
414 }
415 }
416
417 } // namespace ukm 262 } // namespace ukm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698