autofill_metrics.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright 2013 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 "components/autofill/core/browser/autofill_metrics.h"
6
7#include "base/logging.h"
8#include "base/metrics/histogram.h"
9#include "base/metrics/sparse_histogram.h"
10#include "base/time/time.h"
11#include "components/autofill/core/browser/autofill_type.h"
12#include "components/autofill/core/browser/form_structure.h"
13#include "components/autofill/core/common/form_data.h"
14
15namespace autofill {
16
17namespace {
18
19// Server experiments we support.
20enum ServerExperiment {
21  NO_EXPERIMENT = 0,
22  UNKNOWN_EXPERIMENT,
23  ACCEPTANCE_RATIO_06,
24  ACCEPTANCE_RATIO_1,
25  ACCEPTANCE_RATIO_2,
26  ACCEPTANCE_RATIO_4,
27  ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15,
28  ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25,
29  ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5,
30  TOOLBAR_DATA_ONLY,
31  ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4,
32  NO_SERVER_RESPONSE,
33  PROBABILITY_PICKER_05,
34  PROBABILITY_PICKER_025,
35  PROBABILITY_PICKER_025_CC_THRESHOLD_03,
36  PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03,
37  PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK,
38  PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1,
39  NUM_SERVER_EXPERIMENTS
40};
41
42enum FieldTypeGroupForMetrics {
43  AMBIGUOUS = 0,
44  NAME,
45  COMPANY,
46  ADDRESS_LINE_1,
47  ADDRESS_LINE_2,
48  ADDRESS_CITY,
49  ADDRESS_STATE,
50  ADDRESS_ZIP,
51  ADDRESS_COUNTRY,
52  PHONE,
53  FAX,  // Deprecated.
54  EMAIL,
55  CREDIT_CARD_NAME,
56  CREDIT_CARD_NUMBER,
57  CREDIT_CARD_DATE,
58  CREDIT_CARD_TYPE,
59  NUM_FIELD_TYPE_GROUPS_FOR_METRICS
60};
61
62// First, translates |field_type| to the corresponding logical |group| from
63// |FieldTypeGroupForMetrics|.  Then, interpolates this with the given |metric|,
64// which should be in the range [0, |num_possible_metrics|).
65// Returns the interpolated index.
66//
67// The interpolation maps the pair (|group|, |metric|) to a single index, so
68// that all the indicies for a given group are adjacent.  In particular, with
69// the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH,
70// MISMATCH}, we create this set of mapped indices:
71// {
72//   AMBIGUOUS+UNKNOWN,
73//   AMBIGUOUS+MATCH,
74//   AMBIGUOUS+MISMATCH,
75//   NAME+UNKNOWN,
76//   NAME+MATCH,
77//   NAME+MISMATCH,
78//   ...
79// }.
80//
81// Clients must ensure that |field_type| is one of the types Chrome supports
82// natively, e.g. |field_type| must not be a billng address.
83int GetFieldTypeGroupMetric(const ServerFieldType field_type,
84                            const int metric,
85                            const int num_possible_metrics) {
86  DCHECK_LT(metric, num_possible_metrics);
87
88  FieldTypeGroupForMetrics group;
89  switch (AutofillType(field_type).group()) {
90    case ::autofill::NO_GROUP:
91      group = AMBIGUOUS;
92      break;
93
94    case ::autofill::NAME:
95      group = NAME;
96      break;
97
98    case ::autofill::COMPANY:
99      group = COMPANY;
100      break;
101
102    case ::autofill::ADDRESS_HOME:
103      switch (field_type) {
104        case ADDRESS_HOME_LINE1:
105          group = ADDRESS_LINE_1;
106          break;
107        case ADDRESS_HOME_LINE2:
108          group = ADDRESS_LINE_2;
109          break;
110        case ADDRESS_HOME_CITY:
111          group = ADDRESS_CITY;
112          break;
113        case ADDRESS_HOME_STATE:
114          group = ADDRESS_STATE;
115          break;
116        case ADDRESS_HOME_ZIP:
117          group = ADDRESS_ZIP;
118          break;
119        case ADDRESS_HOME_COUNTRY:
120          group = ADDRESS_COUNTRY;
121          break;
122        default:
123          NOTREACHED();
124          group = AMBIGUOUS;
125      }
126      break;
127
128    case ::autofill::EMAIL:
129      group = EMAIL;
130      break;
131
132    case ::autofill::PHONE_HOME:
133      group = PHONE;
134      break;
135
136    case ::autofill::CREDIT_CARD:
137      switch (field_type) {
138        case ::autofill::CREDIT_CARD_NAME:
139          group = CREDIT_CARD_NAME;
140          break;
141        case ::autofill::CREDIT_CARD_NUMBER:
142          group = CREDIT_CARD_NUMBER;
143          break;
144        case ::autofill::CREDIT_CARD_TYPE:
145          group = CREDIT_CARD_TYPE;
146          break;
147        default:
148          group = CREDIT_CARD_DATE;
149      }
150      break;
151
152    default:
153      NOTREACHED();
154      group = AMBIGUOUS;
155  }
156
157  // Interpolate the |metric| with the |group|, so that all metrics for a given
158  // |group| are adjacent.
159  return (group * num_possible_metrics) + metric;
160}
161
162std::string WalletApiMetricToString(
163    AutofillMetrics::WalletApiCallMetric metric) {
164  switch (metric) {
165    case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS:
166      return "AcceptLegalDocuments";
167    case AutofillMetrics::AUTHENTICATE_INSTRUMENT:
168      return "AuthenticateInstrument";
169    case AutofillMetrics::GET_FULL_WALLET:
170      return "GetFullWallet";
171    case AutofillMetrics::GET_WALLET_ITEMS:
172      return "GetWalletItems";
173    case AutofillMetrics::SAVE_TO_WALLET:
174      return "SaveToWallet";
175    case AutofillMetrics::UNKNOWN_API_CALL:
176    case AutofillMetrics::NUM_WALLET_API_CALLS:
177      NOTREACHED();
178      return "UnknownApiCall";
179  }
180
181  NOTREACHED();
182  return "UnknownApiCall";
183}
184
185// A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
186// to vary over the program's runtime.
187void LogUMAHistogramEnumeration(const std::string& name,
188                                int sample,
189                                int boundary_value) {
190  DCHECK_LT(sample, boundary_value);
191
192  // Note: This leaks memory, which is expected behavior.
193  base::HistogramBase* histogram =
194      base::LinearHistogram::FactoryGet(
195          name,
196          1,
197          boundary_value,
198          boundary_value + 1,
199          base::HistogramBase::kUmaTargetedHistogramFlag);
200  histogram->Add(sample);
201}
202
203// A version of the UMA_HISTOGRAM_TIMES macro that allows the |name|
204// to vary over the program's runtime.
205void LogUMAHistogramTimes(const std::string& name,
206                          const base::TimeDelta& duration) {
207  // Note: This leaks memory, which is expected behavior.
208  base::HistogramBase* histogram =
209      base::Histogram::FactoryTimeGet(
210          name,
211          base::TimeDelta::FromMilliseconds(1),
212          base::TimeDelta::FromSeconds(10),
213          50,
214          base::HistogramBase::kUmaTargetedHistogramFlag);
215  histogram->AddTime(duration);
216}
217
218// A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name|
219// to vary over the program's runtime.
220void LogUMAHistogramLongTimes(const std::string& name,
221                              const base::TimeDelta& duration) {
222  // Note: This leaks memory, which is expected behavior.
223  base::HistogramBase* histogram =
224      base::Histogram::FactoryTimeGet(
225          name,
226          base::TimeDelta::FromMilliseconds(1),
227          base::TimeDelta::FromHours(1),
228          50,
229          base::HistogramBase::kUmaTargetedHistogramFlag);
230  histogram->AddTime(duration);
231}
232
233// Logs a type quality metric.  The primary histogram name is constructed based
234// on |base_name| and |experiment_id|.  The field-specific histogram name also
235// factors in the |field_type|.  Logs a sample of |metric|, which should be in
236// the range [0, |num_possible_metrics|).
237void LogTypeQualityMetric(const std::string& base_name,
238                          const int metric,
239                          const int num_possible_metrics,
240                          const ServerFieldType field_type,
241                          const std::string& experiment_id) {
242  DCHECK_LT(metric, num_possible_metrics);
243
244  std::string histogram_name = base_name;
245  if (!experiment_id.empty())
246    histogram_name += "_" + experiment_id;
247  LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics);
248
249  std::string sub_histogram_name = base_name + ".ByFieldType";
250  if (!experiment_id.empty())
251    sub_histogram_name += "_" + experiment_id;
252  const int field_type_group_metric =
253      GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics);
254  const int num_field_type_group_metrics =
255      num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS;
256  LogUMAHistogramEnumeration(sub_histogram_name,
257                             field_type_group_metric,
258                             num_field_type_group_metrics);
259}
260
261void LogServerExperimentId(const std::string& histogram_name,
262                           const std::string& experiment_id) {
263  ServerExperiment metric = UNKNOWN_EXPERIMENT;
264
265  const std::string default_experiment_name =
266      FormStructure(FormData()).server_experiment_id();
267  if (experiment_id.empty())
268    metric = NO_EXPERIMENT;
269  else if (experiment_id == "ar06")
270    metric = ACCEPTANCE_RATIO_06;
271  else if (experiment_id == "ar1")
272    metric = ACCEPTANCE_RATIO_1;
273  else if (experiment_id == "ar2")
274    metric = ACCEPTANCE_RATIO_2;
275  else if (experiment_id == "ar4")
276    metric = ACCEPTANCE_RATIO_4;
277  else if (experiment_id == "ar05wlr15")
278    metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15;
279  else if (experiment_id == "ar05wlr25")
280    metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25;
281  else if (experiment_id == "ar05wr15fs5")
282    metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5;
283  else if (experiment_id == "tbar1")
284    metric = TOOLBAR_DATA_ONLY;
285  else if (experiment_id == "ar04wr3fs4")
286    metric = ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4;
287  else if (experiment_id == default_experiment_name)
288    metric = NO_SERVER_RESPONSE;
289  else if (experiment_id == "fp05")
290    metric = PROBABILITY_PICKER_05;
291  else if (experiment_id == "fp025")
292    metric = PROBABILITY_PICKER_025;
293  else if (experiment_id == "fp05cc03")
294    metric = PROBABILITY_PICKER_025_CC_THRESHOLD_03;
295  else if (experiment_id == "fp05cco03")
296    metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03;
297  else if (experiment_id == "fp05cco03cstd")
298    metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK;
299  else if (experiment_id == "fp05cc03e1")
300    metric = PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1;
301
302  DCHECK_LT(metric, NUM_SERVER_EXPERIMENTS);
303  LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS);
304}
305
306}  // namespace
307
308AutofillMetrics::AutofillMetrics() {
309}
310
311AutofillMetrics::~AutofillMetrics() {
312}
313
314void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const {
315  DCHECK_LT(metric, NUM_INFO_BAR_METRICS);
316
317  UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
318                            NUM_INFO_BAR_METRICS);
319}
320
321void AutofillMetrics::LogDialogDismissalState(
322    DialogDismissalState state) const {
323  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
324                            state, NUM_DIALOG_DISMISSAL_STATES);
325}
326
327void AutofillMetrics::LogDialogInitialUserState(
328    DialogInitialUserStateMetric user_type) const {
329  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
330                            user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS);
331}
332
333void AutofillMetrics::LogDialogLatencyToShow(
334    const base::TimeDelta& duration) const {
335  LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
336}
337
338void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
339  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
340                            event, NUM_DIALOG_POPUP_EVENTS);
341}
342
343void AutofillMetrics::LogDialogSecurityMetric(
344    DialogSecurityMetric metric) const {
345  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
346                            metric, NUM_DIALOG_SECURITY_METRICS);
347}
348
349void AutofillMetrics::LogDialogUiDuration(
350    const base::TimeDelta& duration,
351    DialogDismissalAction dismissal_action) const {
352  std::string suffix;
353  switch (dismissal_action) {
354    case DIALOG_ACCEPTED:
355      suffix = "Submit";
356      break;
357
358    case DIALOG_CANCELED:
359      suffix = "Cancel";
360      break;
361  }
362
363  LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration);
364  LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix,
365                           duration);
366}
367
368void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
369  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
370                            NUM_DIALOG_UI_EVENTS);
371}
372
373void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
374  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
375                            NUM_WALLET_ERROR_METRICS);
376}
377
378void AutofillMetrics::LogWalletApiCallDuration(
379    WalletApiCallMetric metric,
380    const base::TimeDelta& duration) const {
381  LogUMAHistogramTimes("Wallet.ApiCallDuration." +
382                       WalletApiMetricToString(metric), duration);
383}
384
385void AutofillMetrics::LogWalletMalformedResponseMetric(
386    WalletApiCallMetric metric) const {
387  UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
388                            NUM_WALLET_API_CALLS);
389}
390
391void AutofillMetrics::LogWalletRequiredActionMetric(
392      WalletRequiredActionMetric required_action) const {
393  UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
394                            required_action, NUM_WALLET_REQUIRED_ACTIONS);
395}
396
397void AutofillMetrics::LogWalletResponseCode(int response_code) const {
398  UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
399}
400
401void AutofillMetrics::LogDeveloperEngagementMetric(
402    DeveloperEngagementMetric metric) const {
403  DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS);
404
405  UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric,
406                            NUM_DEVELOPER_ENGAGEMENT_METRICS);
407}
408
409void AutofillMetrics::LogHeuristicTypePrediction(
410    FieldTypeQualityMetric metric,
411    ServerFieldType field_type,
412    const std::string& experiment_id) const {
413  LogTypeQualityMetric("Autofill.Quality.HeuristicType",
414                       metric, NUM_FIELD_TYPE_QUALITY_METRICS,
415                       field_type, experiment_id);
416}
417
418void AutofillMetrics::LogOverallTypePrediction(
419    FieldTypeQualityMetric metric,
420    ServerFieldType field_type,
421    const std::string& experiment_id) const {
422  LogTypeQualityMetric("Autofill.Quality.PredictedType",
423                       metric, NUM_FIELD_TYPE_QUALITY_METRICS,
424                       field_type, experiment_id);
425}
426
427void AutofillMetrics::LogServerTypePrediction(
428    FieldTypeQualityMetric metric,
429    ServerFieldType field_type,
430    const std::string& experiment_id) const {
431  LogTypeQualityMetric("Autofill.Quality.ServerType",
432                       metric, NUM_FIELD_TYPE_QUALITY_METRICS,
433                       field_type, experiment_id);
434}
435
436void AutofillMetrics::LogQualityMetric(QualityMetric metric,
437                                       const std::string& experiment_id) const {
438  DCHECK_LT(metric, NUM_QUALITY_METRICS);
439
440  std::string histogram_name = "Autofill.Quality";
441  if (!experiment_id.empty())
442    histogram_name += "_" + experiment_id;
443
444  LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS);
445}
446
447void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const {
448  DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS);
449
450  UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
451                            NUM_SERVER_QUERY_METRICS);
452}
453
454void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
455  DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS);
456
457  UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
458                            NUM_USER_HAPPINESS_METRICS);
459}
460
461void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
462    const base::TimeDelta& duration) const {
463  UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
464                             duration,
465                             base::TimeDelta::FromMilliseconds(100),
466                             base::TimeDelta::FromMinutes(10),
467                             50);
468}
469
470void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
471    const base::TimeDelta& duration) const {
472  UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
473                             duration,
474                             base::TimeDelta::FromMilliseconds(100),
475                             base::TimeDelta::FromMinutes(10),
476                             50);
477}
478
479void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
480    const base::TimeDelta& duration) const {
481  UMA_HISTOGRAM_CUSTOM_TIMES(
482      "Autofill.FillDuration.FromInteraction.WithAutofill",
483      duration,
484      base::TimeDelta::FromMilliseconds(100),
485      base::TimeDelta::FromMinutes(10),
486      50);
487}
488
489void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
490    const base::TimeDelta& duration) const {
491  UMA_HISTOGRAM_CUSTOM_TIMES(
492       "Autofill.FillDuration.FromInteraction.WithoutAutofill",
493       duration,
494       base::TimeDelta::FromMilliseconds(100),
495       base::TimeDelta::FromMinutes(10),
496       50);
497}
498
499void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
500  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
501}
502
503void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
504  UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
505}
506
507void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
508  UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
509}
510
511void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
512  UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
513}
514
515void AutofillMetrics::LogServerExperimentIdForQuery(
516    const std::string& experiment_id) const {
517  LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id);
518}
519
520void AutofillMetrics::LogServerExperimentIdForUpload(
521    const std::string& experiment_id) const {
522  LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id);
523}
524
525}  // namespace autofill
526