blob: 9e2406114e6b50d1be4b6f8901b7bbdab4a247be [file] [log] [blame]
// Copyright (c) 2011 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 "chrome/browser/autofill/autofill_metrics.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/form_structure.h"
#include "webkit/glue/form_data.h"
namespace {
// Server experiments we support.
enum ServerExperiment {
NO_EXPERIMENT = 0,
UNKNOWN_EXPERIMENT,
ACCEPTANCE_RATIO_06,
ACCEPTANCE_RATIO_1,
ACCEPTANCE_RATIO_2,
ACCEPTANCE_RATIO_4,
ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15,
ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25,
ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5,
TOOLBAR_DATA_ONLY,
ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4,
NO_SERVER_RESPONSE,
PROBABILITY_PICKER_05,
NUM_SERVER_EXPERIMENTS
};
enum FieldTypeGroupForMetrics {
AMBIGUOUS = 0,
NAME,
COMPANY,
ADDRESS_LINE_1,
ADDRESS_LINE_2,
ADDRESS_CITY,
ADDRESS_STATE,
ADDRESS_ZIP,
ADDRESS_COUNTRY,
PHONE,
FAX, // Deprecated.
EMAIL,
CREDIT_CARD_NAME,
CREDIT_CARD_NUMBER,
CREDIT_CARD_DATE,
NUM_FIELD_TYPE_GROUPS_FOR_METRICS
};
// First, translates |field_type| to the corresponding logical |group| from
// |FieldTypeGroupForMetrics|. Then, interpolates this with the given |metric|,
// which should be in the range [0, |num_possible_metrics|).
// Returns the interpolated index.
//
// The interpolation maps the pair (|group|, |metric|) to a single index, so
// that all the indicies for a given group are adjacent. In particular, with
// the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH,
// MISMATCH}, we create this set of mapped indices:
// {
// AMBIGUOUS+UNKNOWN,
// AMBIGUOUS+MATCH,
// AMBIGUOUS+MISMATCH,
// NAME+UNKNOWN,
// NAME+MATCH,
// NAME+MISMATCH,
// ...
// }.
//
// Clients must ensure that |field_type| is one of the types Chrome supports
// natively, e.g. |field_type| must not be a billng address.
int GetFieldTypeGroupMetric(const AutofillFieldType field_type,
const int metric,
const int num_possible_metrics) {
DCHECK(metric < num_possible_metrics);
FieldTypeGroupForMetrics group;
switch (AutofillType(field_type).group()) {
case AutofillType::NO_GROUP:
group = AMBIGUOUS;
break;
case AutofillType::NAME:
group = NAME;
break;
case AutofillType::COMPANY:
group = COMPANY;
break;
case AutofillType::ADDRESS_HOME:
switch (field_type) {
case ADDRESS_HOME_LINE1:
group = ADDRESS_LINE_1;
break;
case ADDRESS_HOME_LINE2:
group = ADDRESS_LINE_2;
break;
case ADDRESS_HOME_CITY:
group = ADDRESS_CITY;
break;
case ADDRESS_HOME_STATE:
group = ADDRESS_STATE;
break;
case ADDRESS_HOME_ZIP:
group = ADDRESS_ZIP;
break;
case ADDRESS_HOME_COUNTRY:
group = ADDRESS_COUNTRY;
break;
default:
NOTREACHED();
group = AMBIGUOUS;
}
break;
case AutofillType::EMAIL:
group = EMAIL;
break;
case AutofillType::PHONE:
group = PHONE;
break;
case AutofillType::CREDIT_CARD:
switch (field_type) {
case ::CREDIT_CARD_NAME:
group = CREDIT_CARD_NAME;
break;
case ::CREDIT_CARD_NUMBER:
group = CREDIT_CARD_NUMBER;
break;
default:
group = CREDIT_CARD_DATE;
}
break;
default:
NOTREACHED();
group = AMBIGUOUS;
}
// Interpolate the |metric| with the |group|, so that all metrics for a given
// |group| are adjacent.
return (group * num_possible_metrics) + metric;
}
// A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
// to vary over the program's runtime.
void LogUMAHistogramEnumeration(const std::string& name,
int sample,
int boundary_value) {
// We can't use the UMA_HISTOGRAM_ENUMERATION macro here because the histogram
// name can vary over the duration of the program.
// Note that this leaks memory; that is expected behavior.
base::Histogram* counter =
base::LinearHistogram::FactoryGet(
name,
1,
boundary_value,
boundary_value + 1,
base::Histogram::kUmaTargetedHistogramFlag);
counter->Add(sample);
}
// Logs a type quality metric. The primary histogram name is constructed based
// on |base_name| and |experiment_id|. The field-specific histogram name also
// factors in the |field_type|. Logs a sample of |metric|, which should be in
// the range [0, |num_possible_metrics|).
void LogTypeQualityMetric(const std::string& base_name,
const int metric,
const int num_possible_metrics,
const AutofillFieldType field_type,
const std::string& experiment_id) {
DCHECK(metric < num_possible_metrics);
std::string histogram_name = base_name;
if (!experiment_id.empty())
histogram_name += "_" + experiment_id;
LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics);
std::string sub_histogram_name = base_name + ".ByFieldType";
if (!experiment_id.empty())
sub_histogram_name += "_" + experiment_id;
const int field_type_group_metric =
GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics);
const int num_field_type_group_metrics =
num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS;
LogUMAHistogramEnumeration(sub_histogram_name,
field_type_group_metric,
num_field_type_group_metrics);
}
void LogServerExperimentId(const std::string& histogram_name,
const std::string& experiment_id) {
ServerExperiment metric = UNKNOWN_EXPERIMENT;
const std::string default_experiment_name =
FormStructure(webkit_glue::FormData()).server_experiment_id();
if (experiment_id.empty())
metric = NO_EXPERIMENT;
else if (experiment_id == "ar06")
metric = ACCEPTANCE_RATIO_06;
else if (experiment_id == "ar1")
metric = ACCEPTANCE_RATIO_1;
else if (experiment_id == "ar2")
metric = ACCEPTANCE_RATIO_2;
else if (experiment_id == "ar4")
metric = ACCEPTANCE_RATIO_4;
else if (experiment_id == "ar05wlr15")
metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15;
else if (experiment_id == "ar05wlr25")
metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25;
else if (experiment_id == "ar05wr15fs5")
metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5;
else if (experiment_id == "tbar1")
metric = TOOLBAR_DATA_ONLY;
else if (experiment_id == "ar04wr3fs4")
metric = ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4;
else if (experiment_id == default_experiment_name)
metric = NO_SERVER_RESPONSE;
else if (experiment_id == "fp05")
metric = PROBABILITY_PICKER_05;
DCHECK(metric < NUM_SERVER_EXPERIMENTS);
LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS);
}
} // namespace
AutofillMetrics::AutofillMetrics() {
}
AutofillMetrics::~AutofillMetrics() {
}
void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const {
DCHECK(metric < NUM_INFO_BAR_METRICS);
UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
NUM_INFO_BAR_METRICS);
}
void AutofillMetrics::LogHeuristicTypePrediction(
FieldTypeQualityMetric metric,
AutofillFieldType field_type,
const std::string& experiment_id) const {
LogTypeQualityMetric("Autofill.Quality.HeuristicType",
metric, NUM_FIELD_TYPE_QUALITY_METRICS,
field_type, experiment_id);
}
void AutofillMetrics::LogOverallTypePrediction(
FieldTypeQualityMetric metric,
AutofillFieldType field_type,
const std::string& experiment_id) const {
LogTypeQualityMetric("Autofill.Quality.PredictedType",
metric, NUM_FIELD_TYPE_QUALITY_METRICS,
field_type, experiment_id);
}
void AutofillMetrics::LogServerTypePrediction(
FieldTypeQualityMetric metric,
AutofillFieldType field_type,
const std::string& experiment_id) const {
LogTypeQualityMetric("Autofill.Quality.ServerType",
metric, NUM_FIELD_TYPE_QUALITY_METRICS,
field_type, experiment_id);
}
void AutofillMetrics::LogQualityMetric(QualityMetric metric,
const std::string& experiment_id) const {
DCHECK(metric < NUM_QUALITY_METRICS);
std::string histogram_name = "Autofill.Quality";
if (!experiment_id.empty())
histogram_name += "_" + experiment_id;
LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS);
}
void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const {
DCHECK(metric < NUM_SERVER_QUERY_METRICS);
UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
NUM_SERVER_QUERY_METRICS);
}
void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
DCHECK(metric < NUM_USER_HAPPINESS_METRICS);
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
NUM_USER_HAPPINESS_METRICS);
}
void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
const base::TimeDelta& duration) const {
UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
duration,
base::TimeDelta::FromMilliseconds(100),
base::TimeDelta::FromMinutes(10),
50);
}
void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
const base::TimeDelta& duration) const {
UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
duration,
base::TimeDelta::FromMilliseconds(100),
base::TimeDelta::FromMinutes(10),
50);
}
void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
const base::TimeDelta& duration) const {
UMA_HISTOGRAM_CUSTOM_TIMES(
"Autofill.FillDuration.FromInteraction.WithAutofill",
duration,
base::TimeDelta::FromMilliseconds(100),
base::TimeDelta::FromMinutes(10),
50);
}
void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
const base::TimeDelta& duration) const {
UMA_HISTOGRAM_CUSTOM_TIMES(
"Autofill.FillDuration.FromInteraction.WithoutAutofill",
duration,
base::TimeDelta::FromMilliseconds(100),
base::TimeDelta::FromMinutes(10),
50);
}
void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
}
void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
}
void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
}
void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
}
void AutofillMetrics::LogServerExperimentIdForQuery(
const std::string& experiment_id) const {
LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id);
}
void AutofillMetrics::LogServerExperimentIdForUpload(
const std::string& experiment_id) const {
LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id);
}