1// Copyright (c) 2011 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 "chrome/browser/autofill/autofill_metrics.h"
6
7#include "base/logging.h"
8#include "base/metrics/histogram.h"
9#include "chrome/browser/autofill/autofill_type.h"
10
11namespace {
12
13enum FieldTypeGroupForMetrics {
14  AMBIGUOUS = 0,
15  NAME,
16  COMPANY,
17  ADDRESS_LINE_1,
18  ADDRESS_LINE_2,
19  ADDRESS_CITY,
20  ADDRESS_STATE,
21  ADDRESS_ZIP,
22  ADDRESS_COUNTRY,
23  PHONE,
24  FAX,
25  EMAIL,
26  CREDIT_CARD_NAME,
27  CREDIT_CARD_NUMBER,
28  CREDIT_CARD_DATE,
29  NUM_FIELD_TYPE_GROUPS_FOR_METRICS
30};
31
32// Translates |field_type| to the corresponding logical grouping for metrics,
33// and then interpolates this with the given |metric|, which should be in the
34// range [0, |num_possible_metrics|).  Returns the interpolated metric.
35// Clients must ensure that |field_type| is one of the types Chrome supports
36// natively, e.g. |field_type| must not be a billng address.
37int GetFieldTypeGroupMetric(const AutofillFieldType field_type,
38                            const int metric,
39                            const int num_possible_metrics) {
40  DCHECK(metric < num_possible_metrics);
41
42  FieldTypeGroupForMetrics group;
43  switch (AutofillType(field_type).group()) {
44    case AutofillType::NO_GROUP:
45      group = AMBIGUOUS;
46      break;
47
48    case AutofillType::NAME:
49      group = NAME;
50      break;
51
52    case AutofillType::COMPANY:
53      group = COMPANY;
54      break;
55
56    case AutofillType::ADDRESS_HOME:
57      switch (field_type) {
58        case ADDRESS_HOME_LINE1:
59          group = ADDRESS_LINE_1;
60          break;
61        case ADDRESS_HOME_LINE2:
62          group = ADDRESS_LINE_2;
63          break;
64        case ADDRESS_HOME_CITY:
65          group = ADDRESS_CITY;
66          break;
67        case ADDRESS_HOME_STATE:
68          group = ADDRESS_STATE;
69          break;
70        case ADDRESS_HOME_ZIP:
71          group = ADDRESS_ZIP;
72          break;
73        case ADDRESS_HOME_COUNTRY:
74          group = ADDRESS_COUNTRY;
75          break;
76        default:
77          NOTREACHED();
78          group = AMBIGUOUS;
79      }
80      break;
81
82    case AutofillType::EMAIL:
83      group = EMAIL;
84      break;
85
86    case AutofillType::PHONE_HOME:
87      group = PHONE;
88      break;
89
90    case AutofillType::PHONE_FAX:
91      group = FAX;
92      break;
93
94    case AutofillType::CREDIT_CARD:
95      switch (field_type) {
96        case ::CREDIT_CARD_NAME:
97          group = CREDIT_CARD_NAME;
98          break;
99        case ::CREDIT_CARD_NUMBER:
100          group = CREDIT_CARD_NUMBER;
101          break;
102        default:
103          group = CREDIT_CARD_DATE;
104      }
105      break;
106
107    default:
108      NOTREACHED();
109      group = AMBIGUOUS;
110  }
111
112  // Interpolate the |metric| with the |group|, so that all metrics for a given
113  // |group| are adjacent.  The resulting metrics will be arranged as:
114  // AMBIGUOUS_UNKNOWN
115  // AMBIGUOUS_MATCH
116  // AMBIGUOUS_MISMATCH
117  // NAME_UNKNOWN
118  // NAME_MATCH
119  // NAME_MISMATCH
120  // ...
121  return (group * num_possible_metrics) + metric;
122}
123
124// A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
125// to vary over the program's runtime.
126void LogUMAHistogramEnumeration(const std::string& name,
127                                int sample,
128                                int boundary_value) {
129  // We can't use the UMA_HISTOGRAM_ENUMERATION macro here because the histogram
130  // name can vary over the duration of the program.
131  // Note that this leaks memory; that is expected behavior.
132  base::Histogram* counter =
133      base::LinearHistogram::FactoryGet(
134          name,
135          1,
136          boundary_value,
137          boundary_value + 1,
138          base::Histogram::kUmaTargetedHistogramFlag);
139  counter->Add(sample);
140}
141
142// Logs a type quality metric.  The primary histogram name is constructed based
143// on |base_name| and |experiment_id|.  The field-specific histogram name also
144// factors in the |field_type|.  Logs a sample of |metric|, which should be in
145// the range [0, |num_possible_metrics|).
146void LogTypeQualityMetric(const std::string& base_name,
147                          const int metric,
148                          const int num_possible_metrics,
149                          const AutofillFieldType field_type,
150                          const std::string& experiment_id) {
151  DCHECK(metric < num_possible_metrics);
152
153  std::string histogram_name = base_name;
154  if (!experiment_id.empty())
155    histogram_name += "_" + experiment_id;
156  LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics);
157
158  std::string sub_histogram_name = base_name + ".ByFieldType";
159  if (!experiment_id.empty())
160    sub_histogram_name += "_" + experiment_id;
161  const int field_type_group_metric =
162      GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics);
163  const int num_field_type_group_metrics =
164      num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS;
165  LogUMAHistogramEnumeration(sub_histogram_name,
166                             field_type_group_metric,
167                             num_field_type_group_metrics);
168}
169
170}  // namespace
171
172AutofillMetrics::AutofillMetrics() {
173}
174
175AutofillMetrics::~AutofillMetrics() {
176}
177
178void AutofillMetrics::Log(CreditCardInfoBarMetric metric) const {
179  DCHECK(metric < NUM_CREDIT_CARD_INFO_BAR_METRICS);
180
181  UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
182                            NUM_CREDIT_CARD_INFO_BAR_METRICS);
183}
184
185void AutofillMetrics::Log(HeuristicTypeQualityMetric metric,
186                          AutofillFieldType field_type,
187                          const std::string& experiment_id) const {
188  LogTypeQualityMetric("Autofill.Quality.HeuristicType",
189                       metric, NUM_HEURISTIC_TYPE_QUALITY_METRICS,
190                       field_type, experiment_id);
191}
192
193void AutofillMetrics::Log(PredictedTypeQualityMetric metric,
194                          AutofillFieldType field_type,
195                          const std::string& experiment_id) const {
196  LogTypeQualityMetric("Autofill.Quality.PredictedType",
197                       metric, NUM_PREDICTED_TYPE_QUALITY_METRICS,
198                       field_type, experiment_id);
199}
200
201void AutofillMetrics::Log(QualityMetric metric,
202                          const std::string& experiment_id) const {
203  DCHECK(metric < NUM_QUALITY_METRICS);
204
205  std::string histogram_name = "Autofill.Quality";
206  if (!experiment_id.empty())
207    histogram_name += "_" + experiment_id;
208
209  LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS);
210}
211
212void AutofillMetrics::Log(ServerQueryMetric metric) const {
213  DCHECK(metric < NUM_SERVER_QUERY_METRICS);
214
215  UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
216                            NUM_SERVER_QUERY_METRICS);
217}
218
219void AutofillMetrics::Log(ServerTypeQualityMetric metric,
220                          AutofillFieldType field_type,
221                          const std::string& experiment_id) const {
222  LogTypeQualityMetric("Autofill.Quality.ServerType",
223                       metric, NUM_SERVER_TYPE_QUALITY_METRICS,
224                       field_type, experiment_id);
225}
226
227void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
228  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
229}
230
231void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
232  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
233}
234
235void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
236  UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
237}
238
239void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
240  UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
241}
242