blob: 26c7ea3e63e9fc7d21ceeca9ebeee6a32c11147a [file] [log] [blame]
// 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