| Index: components/ukm/ukm_recorder_impl.cc
|
| diff --git a/components/ukm/ukm_recorder_impl.cc b/components/ukm/ukm_recorder_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0ec456dd302c418f98c4f6b7f7515f0961b6529c
|
| --- /dev/null
|
| +++ b/components/ukm/ukm_recorder_impl.cc
|
| @@ -0,0 +1,175 @@
|
| +// Copyright 2017 The Chromium 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 "components/ukm/ukm_recorder_impl.h"
|
| +
|
| +#include "base/metrics/field_trial.h"
|
| +#include "base/metrics/field_trial_params.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| +#include "base/metrics/metrics_hashes.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "components/metrics/proto/ukm/entry.pb.h"
|
| +#include "components/metrics/proto/ukm/report.pb.h"
|
| +#include "components/metrics/proto/ukm/source.pb.h"
|
| +#include "components/ukm/ukm_source.h"
|
| +
|
| +namespace ukm {
|
| +
|
| +namespace {
|
| +
|
| +// Gets the list of whitelisted Entries as string. Format is a comma seperated
|
| +// list of Entry names (as strings).
|
| +std::string GetWhitelistEntries() {
|
| + return base::GetFieldTrialParamValueByFeature(kUkmFeature,
|
| + "WhitelistEntries");
|
| +}
|
| +
|
| +// Gets the maximum number of Sources we'll keep in memory before discarding any
|
| +// new ones being added.
|
| +size_t GetMaxSources() {
|
| + constexpr size_t kDefaultMaxSources = 500;
|
| + return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt(
|
| + kUkmFeature, "MaxSources", kDefaultMaxSources));
|
| +}
|
| +
|
| +// Gets the maximum number of Entries we'll keep in memory before discarding any
|
| +// new ones being added.
|
| +size_t GetMaxEntries() {
|
| + constexpr size_t kDefaultMaxEntries = 5000;
|
| + return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt(
|
| + kUkmFeature, "MaxEntries", kDefaultMaxEntries));
|
| +}
|
| +
|
| +// True if we should record the initial_url field of the UKM Source proto.
|
| +bool ShouldRecordInitialUrl() {
|
| + return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature,
|
| + "RecordInitialUrl", false);
|
| +}
|
| +
|
| +enum class DroppedDataReason {
|
| + NOT_DROPPED = 0,
|
| + RECORDING_DISABLED = 1,
|
| + MAX_HIT = 2,
|
| + NOT_WHITELISTED = 3,
|
| + NUM_DROPPED_DATA_REASONS
|
| +};
|
| +
|
| +void RecordDroppedSource(DroppedDataReason reason) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "UKM.Sources.Dropped", static_cast<int>(reason),
|
| + static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS));
|
| +}
|
| +
|
| +void RecordDroppedEntry(DroppedDataReason reason) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "UKM.Entries.Dropped", static_cast<int>(reason),
|
| + static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS));
|
| +}
|
| +
|
| +void StoreEntryProto(const mojom::UkmEntry& in, Entry* out) {
|
| + DCHECK(!out->has_source_id());
|
| + DCHECK(!out->has_event_hash());
|
| +
|
| + out->set_source_id(in.source_id);
|
| + out->set_event_hash(in.event_hash);
|
| + for (const auto& metric : in.metrics) {
|
| + Entry::Metric* proto_metric = out->add_metrics();
|
| + proto_metric->set_metric_hash(metric->metric_hash);
|
| + proto_metric->set_value(metric->value);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +UkmRecorderImpl::UkmRecorderImpl() : recording_enabled_(false) {}
|
| +UkmRecorderImpl::~UkmRecorderImpl() = default;
|
| +
|
| +void UkmRecorderImpl::EnableRecording() {
|
| + recording_enabled_ = true;
|
| +}
|
| +
|
| +void UkmRecorderImpl::DisableRecording() {
|
| + recording_enabled_ = false;
|
| +}
|
| +
|
| +void UkmRecorderImpl::Purge() {
|
| + sources_.clear();
|
| + entries_.clear();
|
| +}
|
| +
|
| +void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
|
| + for (const auto& kv : sources_) {
|
| + Source* proto_source = report->add_sources();
|
| + kv.second->PopulateProto(proto_source);
|
| + if (!ShouldRecordInitialUrl())
|
| + proto_source->clear_initial_url();
|
| + }
|
| + for (const auto& entry : entries_) {
|
| + Entry* proto_entry = report->add_entries();
|
| + StoreEntryProto(*entry, proto_entry);
|
| + }
|
| +
|
| + UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size());
|
| + UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size());
|
| + sources_.clear();
|
| + entries_.clear();
|
| +}
|
| +
|
| +void UkmRecorderImpl::UpdateSourceURL(ukm::SourceId source_id,
|
| + const GURL& url) {
|
| + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
| +
|
| + if (!recording_enabled_) {
|
| + RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED);
|
| + return;
|
| + }
|
| +
|
| + // Update the pre-existing source if there is any. This happens when the
|
| + // initial URL is different from the committed URL for the same source, e.g.,
|
| + // when there is redirection.
|
| + if (base::ContainsKey(sources_, source_id)) {
|
| + sources_[source_id]->UpdateUrl(url);
|
| + return;
|
| + }
|
| +
|
| + if (sources_.size() >= GetMaxSources()) {
|
| + RecordDroppedSource(DroppedDataReason::MAX_HIT);
|
| + return;
|
| + }
|
| + std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>();
|
| + source->set_id(source_id);
|
| + source->set_url(url);
|
| + sources_.insert(std::make_pair(source_id, std::move(source)));
|
| +}
|
| +
|
| +void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
|
| + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
| +
|
| + if (!recording_enabled_) {
|
| + RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED);
|
| + return;
|
| + }
|
| + if (entries_.size() >= GetMaxEntries()) {
|
| + RecordDroppedEntry(DroppedDataReason::MAX_HIT);
|
| + return;
|
| + }
|
| +
|
| + if (!whitelisted_entry_hashes_.empty() &&
|
| + !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash)) {
|
| + RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED);
|
| + return;
|
| + }
|
| +
|
| + entries_.push_back(std::move(entry));
|
| +}
|
| +
|
| +void UkmRecorderImpl::StoreWhitelistedEntries() {
|
| + const auto entries =
|
| + base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE,
|
| + base::SPLIT_WANT_NONEMPTY);
|
| + for (const auto& entry_string : entries)
|
| + whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string));
|
| +}
|
| +
|
| +} // namespace ukm
|
|
|