Chromium Code Reviews| OLD | NEW |
|---|---|
| (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_recorder_impl.h" | |
| 6 | |
| 7 #include "base/metrics/field_trial.h" | |
| 8 #include "base/metrics/field_trial_params.h" | |
| 9 #include "base/metrics/histogram_macros.h" | |
| 10 #include "base/metrics/metrics_hashes.h" | |
| 11 #include "base/strings/string_split.h" | |
| 12 #include "components/metrics/proto/ukm/entry.pb.h" | |
| 13 #include "components/metrics/proto/ukm/report.pb.h" | |
| 14 #include "components/metrics/proto/ukm/source.pb.h" | |
| 15 #include "components/ukm/ukm_source.h" | |
| 16 | |
| 17 namespace ukm { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // Gets the list of whitelisted Entries as string. Format is a comma seperated | |
| 22 // list of Entry names (as strings). | |
| 23 std::string GetWhitelistEntries() { | |
| 24 return base::GetFieldTrialParamValueByFeature(kUkmFeature, | |
| 25 "WhitelistEntries"); | |
| 26 } | |
| 27 | |
| 28 // Gets the maximum number of Sources we'll keep in memory before discarding any | |
| 29 // new ones being added. | |
| 30 size_t GetMaxSources() { | |
| 31 constexpr size_t kDefaultMaxSources = 500; | |
| 32 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( | |
| 33 kUkmFeature, "MaxSources", kDefaultMaxSources)); | |
| 34 } | |
| 35 | |
| 36 // Gets the maximum number of Entries we'll keep in memory before discarding any | |
| 37 // new ones being added. | |
| 38 size_t GetMaxEntries() { | |
| 39 constexpr size_t kDefaultMaxEntries = 5000; | |
| 40 return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( | |
| 41 kUkmFeature, "MaxEntries", kDefaultMaxEntries)); | |
| 42 } | |
| 43 | |
| 44 // True if we should record the initial_url field of the UKM Source proto. | |
| 45 bool ShouldRecordInitialUrl() { | |
| 46 return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, | |
| 47 "RecordInitialUrl", false); | |
| 48 } | |
| 49 | |
| 50 enum class DroppedDataReason { | |
| 51 NOT_DROPPED = 0, | |
| 52 RECORDING_DISABLED = 1, | |
| 53 MAX_HIT = 2, | |
| 54 NOT_WHITELISTED = 3, | |
| 55 NUM_DROPPED_DATA_REASONS | |
| 56 }; | |
| 57 | |
| 58 void RecordDroppedSource(DroppedDataReason reason) { | |
| 59 UMA_HISTOGRAM_ENUMERATION( | |
| 60 "UKM.Sources.Dropped", static_cast<int>(reason), | |
| 61 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); | |
| 62 } | |
| 63 | |
| 64 void RecordDroppedEntry(DroppedDataReason reason) { | |
| 65 UMA_HISTOGRAM_ENUMERATION( | |
| 66 "UKM.Entries.Dropped", static_cast<int>(reason), | |
| 67 static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); | |
| 68 } | |
| 69 | |
| 70 void StoreEntryProto(const mojom::UkmEntry& in, Entry* out) { | |
| 71 DCHECK(!out->has_source_id()); | |
| 72 DCHECK(!out->has_event_hash()); | |
| 73 | |
| 74 out->set_source_id(in.source_id); | |
| 75 out->set_event_hash(in.event_hash); | |
| 76 for (const auto& metric : in.metrics) { | |
| 77 Entry::Metric* proto_metric = out->add_metrics(); | |
| 78 proto_metric->set_metric_hash(metric->metric_hash); | |
| 79 proto_metric->set_value(metric->value); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 } // namespace | |
| 84 | |
| 85 UkmRecorderImpl::UkmRecorderImpl() : recording_enabled_(false) {} | |
| 86 UkmRecorderImpl::~UkmRecorderImpl() = default; | |
| 87 | |
| 88 void UkmRecorderImpl::EnableRecording() { | |
| 89 recording_enabled_ = true; | |
| 90 } | |
| 91 | |
| 92 void UkmRecorderImpl::DisableRecording() { | |
| 93 recording_enabled_ = false; | |
| 94 } | |
| 95 | |
| 96 void UkmRecorderImpl::Purge() { | |
| 97 sources_.clear(); | |
| 98 entries_.clear(); | |
| 99 } | |
| 100 | |
| 101 void UkmRecorderImpl::StoreRecordingsInReport(Report* report) { | |
| 102 for (const auto& kv : sources_) { | |
| 103 Source* proto_source = report->add_sources(); | |
| 104 kv.second->PopulateProto(proto_source); | |
| 105 if (!ShouldRecordInitialUrl()) | |
| 106 proto_source->clear_initial_url(); | |
| 107 } | |
| 108 for (const auto& entry : entries_) { | |
| 109 Entry* proto_entry = report->add_entries(); | |
| 110 StoreEntryProto(*entry, proto_entry); | |
| 111 } | |
| 112 | |
| 113 UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size()); | |
| 114 UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size()); | |
| 115 sources_.clear(); | |
| 116 entries_.clear(); | |
| 117 } | |
| 118 | |
| 119 void UkmRecorderImpl::UpdateSourceURL(ukm::SourceId source_id, | |
| 120 const GURL& url) { | |
| 121 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | |
| 122 | |
| 123 if (!recording_enabled_) { | |
| 124 RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED); | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 // Update the pre-existing source if there is any. This happens when the | |
| 129 // initial URL is different from the committed URL for the same source, e.g., | |
| 130 // when there is redirection. | |
| 131 if (base::ContainsKey(sources_, source_id)) { | |
| 132 sources_[source_id]->UpdateUrl(url); | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 if (sources_.size() >= GetMaxSources()) { | |
| 137 RecordDroppedSource(DroppedDataReason::MAX_HIT); | |
| 138 return; | |
| 139 } | |
| 140 std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>(); | |
| 141 source->set_id(source_id); | |
| 142 source->set_url(url); | |
| 143 sources_.insert(std::make_pair(source_id, std::move(source))); | |
| 144 } | |
| 145 | |
| 146 void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) { | |
| 147 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | |
| 148 | |
| 149 if (!recording_enabled_) { | |
| 150 RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED); | |
| 151 return; | |
| 152 } | |
| 153 if (entries_.size() >= GetMaxEntries()) { | |
| 154 RecordDroppedEntry(DroppedDataReason::MAX_HIT); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 if (!whitelisted_entry_hashes_.empty() && | |
| 159 !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash)) { | |
| 160 RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED); | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 entries_.push_back(std::move(entry)); | |
| 165 } | |
| 166 | |
| 167 void UkmRecorderImpl::StoreWhitelistedEntries() { | |
| 168 const auto entries = | |
| 169 base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE, | |
| 170 base::SPLIT_WANT_NONEMPTY); | |
| 171 for (const auto& entry_string : entries) { | |
| 172 whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string)); | |
| 173 } | |
|
oystein (OOO til 10th of July)
2017/05/17 18:25:06
nit: Some inconsistency in whether single-line blo
Steven Holte
2017/05/17 20:44:31
Removed it here.
| |
| 174 } | |
| 175 } | |
| OLD | NEW |