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.
5 #include "components/autofill/core/browser/autofill_metrics.h"
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"
19 enum FieldTypeGroupForMetrics
{
28 GROUP_ADDRESS_COUNTRY
,
30 GROUP_FAX
, // Deprecated.
32 GROUP_CREDIT_CARD_NAME
,
33 GROUP_CREDIT_CARD_NUMBER
,
34 GROUP_CREDIT_CARD_DATE
,
35 GROUP_CREDIT_CARD_TYPE
,
38 NUM_FIELD_TYPE_GROUPS_FOR_METRICS
43 // First, translates |field_type| to the corresponding logical |group| from
44 // |FieldTypeGroupForMetrics|. Then, interpolates this with the given |metric|,
45 // which should be in the range [0, |num_possible_metrics|).
46 // Returns the interpolated index.
48 // The interpolation maps the pair (|group|, |metric|) to a single index, so
49 // that all the indicies for a given group are adjacent. In particular, with
50 // the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH,
51 // MISMATCH}, we create this set of mapped indices:
55 // AMBIGUOUS+MISMATCH,
62 // Clients must ensure that |field_type| is one of the types Chrome supports
63 // natively, e.g. |field_type| must not be a billng address.
64 // NOTE: This is defined outside of the anonymous namespace so that it can be
65 // accessed from the unit test file. It is not exposed in the header file,
66 // however, because it is not intended for consumption outside of the metrics
68 int GetFieldTypeGroupMetric(ServerFieldType field_type
,
69 AutofillMetrics::FieldTypeQualityMetric metric
) {
70 DCHECK_LT(metric
, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS
);
72 FieldTypeGroupForMetrics group
= GROUP_AMBIGUOUS
;
73 switch (AutofillType(field_type
).group()) {
75 group
= GROUP_AMBIGUOUS
;
84 group
= GROUP_COMPANY
;
89 switch (AutofillType(field_type
).GetStorableType()) {
90 case ADDRESS_HOME_LINE1
:
91 group
= GROUP_ADDRESS_LINE_1
;
93 case ADDRESS_HOME_LINE2
:
94 group
= GROUP_ADDRESS_LINE_2
;
96 case ADDRESS_HOME_LINE3
:
97 group
= GROUP_ADDRESS_LINE_3
;
99 case ADDRESS_HOME_CITY
:
100 group
= GROUP_ADDRESS_CITY
;
102 case ADDRESS_HOME_STATE
:
103 group
= GROUP_ADDRESS_STATE
;
105 case ADDRESS_HOME_ZIP
:
106 group
= GROUP_ADDRESS_ZIP
;
108 case ADDRESS_HOME_COUNTRY
:
109 group
= GROUP_ADDRESS_COUNTRY
;
113 group
= GROUP_AMBIGUOUS
;
128 switch (field_type
) {
129 case CREDIT_CARD_NAME
:
130 group
= GROUP_CREDIT_CARD_NAME
;
132 case CREDIT_CARD_NUMBER
:
133 group
= GROUP_CREDIT_CARD_NUMBER
;
135 case CREDIT_CARD_TYPE
:
136 group
= GROUP_CREDIT_CARD_TYPE
;
138 case CREDIT_CARD_EXP_MONTH
:
139 case CREDIT_CARD_EXP_2_DIGIT_YEAR
:
140 case CREDIT_CARD_EXP_4_DIGIT_YEAR
:
141 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
:
142 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR
:
143 group
= GROUP_CREDIT_CARD_DATE
;
147 group
= GROUP_AMBIGUOUS
;
153 group
= GROUP_PASSWORD
;
161 // Interpolate the |metric| with the |group|, so that all metrics for a given
162 // |group| are adjacent.
163 return (group
* AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS
) + metric
;
168 std::string
WalletApiMetricToString(
169 AutofillMetrics::WalletApiCallMetric metric
) {
171 case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS
:
172 return "AcceptLegalDocuments";
173 case AutofillMetrics::AUTHENTICATE_INSTRUMENT
:
174 return "AuthenticateInstrument";
175 case AutofillMetrics::GET_FULL_WALLET
:
176 return "GetFullWallet";
177 case AutofillMetrics::GET_WALLET_ITEMS
:
178 return "GetWalletItems";
179 case AutofillMetrics::SAVE_TO_WALLET
:
180 return "SaveToWallet";
181 case AutofillMetrics::UNKNOWN_API_CALL
:
182 case AutofillMetrics::NUM_WALLET_API_CALLS
:
184 return "UnknownApiCall";
188 return "UnknownApiCall";
191 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
192 // to vary over the program's runtime.
193 void LogUMAHistogramEnumeration(const std::string
& name
,
195 int boundary_value
) {
196 DCHECK_LT(sample
, boundary_value
);
198 // Note: This leaks memory, which is expected behavior.
199 base::HistogramBase
* histogram
=
200 base::LinearHistogram::FactoryGet(
205 base::HistogramBase::kUmaTargetedHistogramFlag
);
206 histogram
->Add(sample
);
209 // A version of the UMA_HISTOGRAM_TIMES macro that allows the |name|
210 // to vary over the program's runtime.
211 void LogUMAHistogramTimes(const std::string
& name
,
212 const base::TimeDelta
& duration
) {
213 // Note: This leaks memory, which is expected behavior.
214 base::HistogramBase
* histogram
=
215 base::Histogram::FactoryTimeGet(
217 base::TimeDelta::FromMilliseconds(1),
218 base::TimeDelta::FromSeconds(10),
220 base::HistogramBase::kUmaTargetedHistogramFlag
);
221 histogram
->AddTime(duration
);
224 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name|
225 // to vary over the program's runtime.
226 void LogUMAHistogramLongTimes(const std::string
& name
,
227 const base::TimeDelta
& duration
) {
228 // Note: This leaks memory, which is expected behavior.
229 base::HistogramBase
* histogram
=
230 base::Histogram::FactoryTimeGet(
232 base::TimeDelta::FromMilliseconds(1),
233 base::TimeDelta::FromHours(1),
235 base::HistogramBase::kUmaTargetedHistogramFlag
);
236 histogram
->AddTime(duration
);
239 // Logs a type quality metric. The primary histogram name is constructed based
240 // on |base_name|. The field-specific histogram name also factors in the
241 // |field_type|. Logs a sample of |metric|, which should be in the range
242 // [0, |num_possible_metrics|).
243 void LogTypeQualityMetric(const std::string
& base_name
,
244 AutofillMetrics::FieldTypeQualityMetric metric
,
245 ServerFieldType field_type
) {
246 DCHECK_LT(metric
, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS
);
248 LogUMAHistogramEnumeration(base_name
, metric
,
249 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS
);
251 int field_type_group_metric
= GetFieldTypeGroupMetric(field_type
, metric
);
252 int num_field_type_group_metrics
=
253 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS
*
254 NUM_FIELD_TYPE_GROUPS_FOR_METRICS
;
255 LogUMAHistogramEnumeration(base_name
+ ".ByFieldType",
256 field_type_group_metric
,
257 num_field_type_group_metrics
);
263 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric
) {
264 DCHECK_LT(metric
, NUM_INFO_BAR_METRICS
);
265 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric
,
266 NUM_INFO_BAR_METRICS
);
270 void AutofillMetrics::LogScanCreditCardPromptMetric(
271 ScanCreditCardPromptMetric metric
) {
272 DCHECK_LT(metric
, NUM_SCAN_CREDIT_CARD_PROMPT_METRICS
);
273 UMA_HISTOGRAM_ENUMERATION("Autofill.ScanCreditCardPrompt", metric
,
274 NUM_SCAN_CREDIT_CARD_PROMPT_METRICS
);
278 void AutofillMetrics::LogScanCreditCardCompleted(
279 const base::TimeDelta
& duration
,
281 std::string suffix
= completed
? "Completed" : "Cancelled";
282 LogUMAHistogramLongTimes("Autofill.ScanCreditCard.Duration_" + suffix
,
284 UMA_HISTOGRAM_BOOLEAN("Autofill.ScanCreditCard.Completed", completed
);
288 void AutofillMetrics::LogDialogDismissalState(DialogDismissalState state
) {
289 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
290 state
, NUM_DIALOG_DISMISSAL_STATES
);
294 void AutofillMetrics::LogDialogInitialUserState(
295 DialogInitialUserStateMetric user_type
) {
296 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
297 user_type
, NUM_DIALOG_INITIAL_USER_STATE_METRICS
);
301 void AutofillMetrics::LogDialogLatencyToShow(const base::TimeDelta
& duration
) {
302 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration
);
306 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event
) {
307 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
308 event
, NUM_DIALOG_POPUP_EVENTS
);
312 void AutofillMetrics::LogDialogSecurityMetric(DialogSecurityMetric metric
) {
313 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
314 metric
, NUM_DIALOG_SECURITY_METRICS
);
318 void AutofillMetrics::LogDialogUiDuration(
319 const base::TimeDelta
& duration
,
320 DialogDismissalAction dismissal_action
) {
322 switch (dismissal_action
) {
323 case DIALOG_ACCEPTED
:
327 case DIALOG_CANCELED
:
332 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration
);
333 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix
,
338 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event
) {
339 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event
,
340 NUM_DIALOG_UI_EVENTS
);
344 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric
) {
345 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric
,
346 NUM_WALLET_ERROR_METRICS
);
350 void AutofillMetrics::LogWalletApiCallDuration(
351 WalletApiCallMetric metric
,
352 const base::TimeDelta
& duration
) {
353 LogUMAHistogramTimes("Wallet.ApiCallDuration." +
354 WalletApiMetricToString(metric
), duration
);
358 void AutofillMetrics::LogWalletMalformedResponseMetric(
359 WalletApiCallMetric metric
) {
360 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric
,
361 NUM_WALLET_API_CALLS
);
365 void AutofillMetrics::LogWalletRequiredActionMetric(
366 WalletRequiredActionMetric required_action
) {
367 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
368 required_action
, NUM_WALLET_REQUIRED_ACTIONS
);
372 void AutofillMetrics::LogWalletResponseCode(int response_code
) {
373 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code
);
377 void AutofillMetrics::LogDeveloperEngagementMetric(
378 DeveloperEngagementMetric metric
) {
379 DCHECK_LT(metric
, NUM_DEVELOPER_ENGAGEMENT_METRICS
);
380 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric
,
381 NUM_DEVELOPER_ENGAGEMENT_METRICS
);
385 void AutofillMetrics::LogHeuristicTypePrediction(FieldTypeQualityMetric metric
,
386 ServerFieldType field_type
) {
387 LogTypeQualityMetric("Autofill.Quality.HeuristicType", metric
, field_type
);
391 void AutofillMetrics::LogOverallTypePrediction(FieldTypeQualityMetric metric
,
392 ServerFieldType field_type
) {
393 LogTypeQualityMetric("Autofill.Quality.PredictedType", metric
, field_type
);
397 void AutofillMetrics::LogServerTypePrediction(FieldTypeQualityMetric metric
,
398 ServerFieldType field_type
) {
399 LogTypeQualityMetric("Autofill.Quality.ServerType", metric
, field_type
);
403 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric
) {
404 DCHECK_LT(metric
, NUM_SERVER_QUERY_METRICS
);
405 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric
,
406 NUM_SERVER_QUERY_METRICS
);
410 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric
) {
411 DCHECK_LT(metric
, NUM_USER_HAPPINESS_METRICS
);
412 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric
,
413 NUM_USER_HAPPINESS_METRICS
);
417 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
418 const base::TimeDelta
& duration
) {
419 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
421 base::TimeDelta::FromMilliseconds(100),
422 base::TimeDelta::FromMinutes(10),
427 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
428 const base::TimeDelta
& duration
) {
429 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
431 base::TimeDelta::FromMilliseconds(100),
432 base::TimeDelta::FromMinutes(10),
437 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
438 const base::TimeDelta
& duration
) {
439 UMA_HISTOGRAM_CUSTOM_TIMES(
440 "Autofill.FillDuration.FromInteraction.WithAutofill",
442 base::TimeDelta::FromMilliseconds(100),
443 base::TimeDelta::FromMinutes(10),
448 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
449 const base::TimeDelta
& duration
) {
450 UMA_HISTOGRAM_CUSTOM_TIMES(
451 "Autofill.FillDuration.FromInteraction.WithoutAutofill",
453 base::TimeDelta::FromMilliseconds(100),
454 base::TimeDelta::FromMinutes(10),
459 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled
) {
460 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled
);
464 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled
) {
465 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled
);
469 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles
) {
470 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles
);
474 void AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
475 size_t num_profiles
) {
476 UMA_HISTOGRAM_COUNTS(
477 "Autofill.StoredProfileCountAtAutofillableFormSubmission", num_profiles
);
481 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions
) {
482 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions
);
485 AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card
)
486 : is_for_credit_card_(is_for_credit_card
),
487 is_server_data_available_(false),
488 is_local_data_available_(false),
489 has_logged_interacted_(false),
490 has_logged_suggestions_shown_(false),
491 has_logged_masked_server_card_suggestion_selected_(false),
492 has_logged_suggestion_filled_(false),
493 has_logged_submitted_(false),
494 logged_suggestion_filled_was_server_data_(false),
495 logged_suggestion_filled_was_masked_server_card_(false) {};
497 void AutofillMetrics::FormEventLogger::OnDidInteractWithAutofillableForm() {
498 if (!has_logged_interacted_
) {
499 has_logged_interacted_
= true;
500 Log(AutofillMetrics::FORM_EVENT_INTERACTED_ONCE
);
504 void AutofillMetrics::FormEventLogger::OnDidShowSuggestions() {
505 Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN
);
506 if (!has_logged_suggestions_shown_
) {
507 has_logged_suggestions_shown_
= true;
508 Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN_ONCE
);
512 void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion() {
513 DCHECK(is_for_credit_card_
);
514 Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED
);
515 if (!has_logged_masked_server_card_suggestion_selected_
) {
516 has_logged_masked_server_card_suggestion_selected_
= true;
518 ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE
);
522 void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
523 const CreditCard
& credit_card
) {
524 DCHECK(is_for_credit_card_
);
525 if (credit_card
.record_type() == CreditCard::MASKED_SERVER_CARD
)
526 Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED
);
527 else if (credit_card
.record_type() == CreditCard::FULL_SERVER_CARD
)
528 Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED
);
530 Log(AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED
);
532 if (!has_logged_suggestion_filled_
) {
533 has_logged_suggestion_filled_
= true;
534 logged_suggestion_filled_was_server_data_
=
535 credit_card
.record_type() == CreditCard::MASKED_SERVER_CARD
||
536 credit_card
.record_type() == CreditCard::FULL_SERVER_CARD
;
537 logged_suggestion_filled_was_masked_server_card_
=
538 credit_card
.record_type() == CreditCard::MASKED_SERVER_CARD
;
539 if (credit_card
.record_type() == CreditCard::MASKED_SERVER_CARD
) {
541 ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE
);
542 } else if (credit_card
.record_type() == CreditCard::FULL_SERVER_CARD
) {
543 Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
);
545 Log(AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE
);
550 void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
551 const AutofillProfile
& profile
) {
552 DCHECK(!is_for_credit_card_
);
553 if (profile
.record_type() == AutofillProfile::SERVER_PROFILE
)
554 Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED
);
556 Log(AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED
);
558 if (!has_logged_suggestion_filled_
) {
559 has_logged_suggestion_filled_
= true;
560 logged_suggestion_filled_was_server_data_
=
561 profile
.record_type() == AutofillProfile::SERVER_PROFILE
;
562 Log(profile
.record_type() == AutofillProfile::SERVER_PROFILE
563 ? AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
564 : AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE
);
568 void AutofillMetrics::FormEventLogger::OnDidSubmitForm() {
569 // Not logging this kind of form if we haven't logged a user interaction.
570 if (!has_logged_interacted_
)
573 // Not logging twice.
574 if (has_logged_submitted_
)
576 has_logged_submitted_
= true;
578 if (!has_logged_suggestion_filled_
) {
579 Log(AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE
);
580 } else if (logged_suggestion_filled_was_masked_server_card_
) {
582 ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE
);
583 } else if (logged_suggestion_filled_was_server_data_
) {
584 Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE
);
586 Log(AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE
);
590 void AutofillMetrics::FormEventLogger::Log(FormEvent event
) const {
591 DCHECK_LT(event
, NUM_FORM_EVENTS
);
592 std::string
name("Autofill.FormEvents.");
593 if (is_for_credit_card_
)
594 name
+= "CreditCard";
597 LogUMAHistogramEnumeration(name
, event
, NUM_FORM_EVENTS
);
599 // Logging again in a different histogram for segmentation purposes.
600 // TODO(waltercacau): Re-evaluate if we still need such fine grained
601 // segmentation. http://crbug.com/454018
602 if (!is_server_data_available_
&& !is_local_data_available_
)
603 name
+= ".WithNoData";
604 else if (is_server_data_available_
&& !is_local_data_available_
)
605 name
+= ".WithOnlyServerData";
606 else if (!is_server_data_available_
&& is_local_data_available_
)
607 name
+= ".WithOnlyLocalData";
609 name
+= ".WithBothServerAndLocalData";
610 LogUMAHistogramEnumeration(name
, event
, NUM_FORM_EVENTS
);
613 } // namespace autofill