| // 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/feature_engagement/internal/stats.h" |
| |
| #include <string> |
| |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/user_metrics.h" |
| #include "components/feature_engagement/public/feature_list.h" |
| |
| namespace feature_engagement { |
| namespace stats { |
| namespace { |
| |
| // Histogram suffixes for database metrics, must match the ones in |
| // histograms.xml. |
| const char kEventStoreSuffix[] = "EventStore"; |
| const char kAvailabilityStoreSuffix[] = "AvailabilityStore"; |
| |
| // A shadow histogram across all features. Also the base name for the suffix |
| // based feature specific histograms; for example for IPH_MyFun, it would be: |
| // InProductHelp.ShouldTriggerHelpUI.IPH_MyFun. |
| const char kShouldTriggerHelpUIHistogram[] = |
| "InProductHelp.ShouldTriggerHelpUI"; |
| |
| // Helper function to log a TriggerHelpUIResult. |
| void LogTriggerHelpUIResult(const std::string& name, |
| TriggerHelpUIResult result) { |
| // Must not use histograms macros here because we pass in the histogram name. |
| base::UmaHistogramEnumeration(name, result, TriggerHelpUIResult::COUNT); |
| base::UmaHistogramEnumeration(kShouldTriggerHelpUIHistogram, result, |
| TriggerHelpUIResult::COUNT); |
| } |
| |
| } // namespace |
| |
| std::string ToDbHistogramSuffix(StoreType type) { |
| switch (type) { |
| case StoreType::EVENTS_STORE: |
| return std::string(kEventStoreSuffix); |
| case StoreType::AVAILABILITY_STORE: |
| return std::string(kAvailabilityStoreSuffix); |
| default: |
| NOTREACHED(); |
| return std::string(); |
| } |
| } |
| |
| void RecordNotifyEvent(const std::string& event_name, |
| const Configuration* config, |
| bool is_model_ready) { |
| DCHECK(!event_name.empty()); |
| DCHECK(config); |
| |
| // Find which feature this event belongs to. |
| const Configuration::ConfigMap& features = |
| config->GetRegisteredFeatureConfigs(); |
| std::string feature_name; |
| for (const auto& element : features) { |
| const std::string fname = element.first; |
| const FeatureConfig& feature_config = element.second; |
| |
| // Track used event separately. |
| if (feature_config.used.name == event_name) { |
| feature_name = fname; |
| DCHECK(!feature_name.empty()); |
| std::string used_event_action = "InProductHelp.NotifyUsedEvent."; |
| used_event_action.append(feature_name); |
| base::RecordComputedAction(used_event_action); |
| break; |
| } |
| |
| // Find if the |event_name| matches any configuration. |
| for (const auto& event : feature_config.event_configs) { |
| if (event.name == event_name) { |
| feature_name = fname; |
| break; |
| } |
| } |
| if (feature_config.trigger.name == event_name) { |
| feature_name = fname; |
| break; |
| } |
| } |
| |
| // Do nothing if no events in the configuration matches the |event_name|. |
| if (feature_name.empty()) |
| return; |
| |
| std::string event_action = "InProductHelp.NotifyEvent."; |
| event_action.append(feature_name); |
| base::RecordComputedAction(event_action); |
| |
| std::string event_histogram = "InProductHelp.NotifyEventReadyState."; |
| event_histogram.append(feature_name); |
| base::UmaHistogramBoolean(event_histogram, is_model_ready); |
| } |
| |
| void RecordShouldTriggerHelpUI(const base::Feature& feature, |
| const FeatureConfig& feature_config, |
| const ConditionValidator::Result& result) { |
| // Records the user action. |
| std::string name = std::string(kShouldTriggerHelpUIHistogram) |
| .append(".") |
| .append(feature.name); |
| base::RecordComputedAction(name); |
| |
| // Total count histogram, used to compute the percentage of each failure type, |
| // in addition to a user action for whether the result was to trigger or not. |
| if (result.NoErrors()) { |
| LogTriggerHelpUIResult(name, |
| feature_config.tracking_only |
| ? TriggerHelpUIResult::SUCCESS_TRACKING_ONLY |
| : TriggerHelpUIResult::SUCCESS); |
| std::string action_name = "InProductHelp.ShouldTriggerHelpUIResult."; |
| action_name.append(feature_config.tracking_only ? "WouldHaveTriggered" |
| : "Triggered"); |
| action_name.append("."); |
| action_name.append(feature.name); |
| base::RecordComputedAction(action_name); |
| } else { |
| LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE); |
| std::string action_name = |
| "InProductHelp.ShouldTriggerHelpUIResult.NotTriggered."; |
| action_name.append(feature.name); |
| base::RecordComputedAction(action_name); |
| } |
| |
| // Histogram about the failure reasons. |
| if (!result.event_model_ready_ok) { |
| LogTriggerHelpUIResult(name, |
| TriggerHelpUIResult::FAILURE_EVENT_MODEL_NOT_READY); |
| } |
| if (!result.currently_showing_ok) { |
| LogTriggerHelpUIResult(name, |
| TriggerHelpUIResult::FAILURE_CURRENTLY_SHOWING); |
| } |
| if (!result.feature_enabled_ok) { |
| LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_FEATURE_DISABLED); |
| } |
| if (!result.config_ok) { |
| LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_CONFIG_INVALID); |
| } |
| if (!result.used_ok) { |
| LogTriggerHelpUIResult( |
| name, TriggerHelpUIResult::FAILURE_USED_PRECONDITION_UNMET); |
| } |
| if (!result.trigger_ok) { |
| LogTriggerHelpUIResult( |
| name, TriggerHelpUIResult::FAILURE_TRIGGER_PRECONDITION_UNMET); |
| } |
| if (!result.preconditions_ok) { |
| LogTriggerHelpUIResult( |
| name, TriggerHelpUIResult::FAILURE_OTHER_PRECONDITION_UNMET); |
| } |
| if (!result.session_rate_ok) { |
| LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_SESSION_RATE); |
| } |
| if (!result.availability_model_ready_ok) { |
| LogTriggerHelpUIResult( |
| name, TriggerHelpUIResult::FAILURE_AVAILABILITY_MODEL_NOT_READY); |
| } |
| if (!result.availability_ok) { |
| LogTriggerHelpUIResult( |
| name, TriggerHelpUIResult::FAILURE_AVAILABILITY_PRECONDITION_UNMET); |
| } |
| if (!result.display_lock_ok) { |
| LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_DISPLAY_LOCK); |
| } |
| } |
| |
| void RecordUserDismiss() { |
| base::RecordAction(base::UserMetricsAction("InProductHelp.Dismissed")); |
| } |
| |
| void RecordDbUpdate(bool success, StoreType type) { |
| std::string histogram_name = |
| "InProductHelp.Db.Update." + ToDbHistogramSuffix(type); |
| base::UmaHistogramBoolean(histogram_name, success); |
| } |
| |
| void RecordDbInitEvent(bool success, StoreType type) { |
| std::string histogram_name = |
| "InProductHelp.Db.Init." + ToDbHistogramSuffix(type); |
| base::UmaHistogramBoolean(histogram_name, success); |
| } |
| |
| void RecordEventDbLoadEvent(bool success, const std::vector<Event>& events) { |
| std::string histogram_name = |
| "InProductHelp.Db.Load." + ToDbHistogramSuffix(StoreType::EVENTS_STORE); |
| base::UmaHistogramBoolean(histogram_name, success); |
| UMA_HISTOGRAM_BOOLEAN("InProductHelp.Db.Load", success); |
| |
| if (!success) |
| return; |
| |
| // Tracks total number of events records when the database is successfully |
| // loaded. |
| int event_count = 0; |
| for (const auto& event : events) |
| event_count += event.events_size(); |
| UMA_HISTOGRAM_COUNTS_1000("InProductHelp.Db.TotalEvents", event_count); |
| } |
| |
| void RecordAvailabilityDbLoadEvent(bool success) { |
| std::string histogram_name = |
| "InProductHelp.Db.Load." + |
| ToDbHistogramSuffix(StoreType::AVAILABILITY_STORE); |
| base::UmaHistogramBoolean(histogram_name, success); |
| UMA_HISTOGRAM_BOOLEAN("InProductHelp.Db.Load", success); |
| } |
| |
| void RecordConfigParsingEvent(ConfigParsingEvent event) { |
| UMA_HISTOGRAM_ENUMERATION("InProductHelp.Config.ParsingEvent", event, |
| ConfigParsingEvent::COUNT); |
| } |
| |
| } // namespace stats |
| } // namespace feature_engagement |