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 // Server experiments we support.
20 enum ServerExperiment {
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,
31 ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4,
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
42 enum FieldTypeGroupForMetrics {
60 NUM_FIELD_TYPE_GROUPS_FOR_METRICS
63 // First, translates |field_type| to the corresponding logical |group| from
64 // |FieldTypeGroupForMetrics|. Then, interpolates this with the given |metric|,
65 // which should be in the range [0, |num_possible_metrics|).
66 // Returns the interpolated index.
68 // The interpolation maps the pair (|group|, |metric|) to a single index, so
69 // that all the indicies for a given group are adjacent. In particular, with
70 // the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH,
71 // MISMATCH}, we create this set of mapped indices:
75 // AMBIGUOUS+MISMATCH,
82 // Clients must ensure that |field_type| is one of the types Chrome supports
83 // natively, e.g. |field_type| must not be a billng address.
84 int GetFieldTypeGroupMetric(const ServerFieldType field_type,
86 const int num_possible_metrics) {
87 DCHECK_LT(metric, num_possible_metrics);
89 FieldTypeGroupForMetrics group = AMBIGUOUS;
90 switch (AutofillType(field_type).group()) {
91 case ::autofill::NO_GROUP:
95 case ::autofill::NAME:
96 case ::autofill::NAME_BILLING:
100 case ::autofill::COMPANY:
104 case ::autofill::ADDRESS_HOME:
105 case ::autofill::ADDRESS_BILLING:
106 switch (AutofillType(field_type).GetStorableType()) {
107 case ADDRESS_HOME_LINE1:
108 group = ADDRESS_LINE_1;
110 case ADDRESS_HOME_LINE2:
111 group = ADDRESS_LINE_2;
113 case ADDRESS_HOME_CITY:
114 group = ADDRESS_CITY;
116 case ADDRESS_HOME_STATE:
117 group = ADDRESS_STATE;
119 case ADDRESS_HOME_ZIP:
122 case ADDRESS_HOME_COUNTRY:
123 group = ADDRESS_COUNTRY;
132 case ::autofill::EMAIL:
136 case ::autofill::PHONE_HOME:
137 case ::autofill::PHONE_BILLING:
141 case ::autofill::CREDIT_CARD:
142 switch (field_type) {
143 case ::autofill::CREDIT_CARD_NAME:
144 group = CREDIT_CARD_NAME;
146 case ::autofill::CREDIT_CARD_NUMBER:
147 group = CREDIT_CARD_NUMBER;
149 case ::autofill::CREDIT_CARD_TYPE:
150 group = CREDIT_CARD_TYPE;
152 case ::autofill::CREDIT_CARD_EXP_MONTH:
153 case ::autofill::CREDIT_CARD_EXP_2_DIGIT_YEAR:
154 case ::autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR:
155 case ::autofill::CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
156 case ::autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
157 group = CREDIT_CARD_DATE;
166 case ::autofill::PASSWORD_FIELD:
171 // Interpolate the |metric| with the |group|, so that all metrics for a given
172 // |group| are adjacent.
173 return (group * num_possible_metrics) + metric;
176 std::string WalletApiMetricToString(
177 AutofillMetrics::WalletApiCallMetric metric) {
179 case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS:
180 return "AcceptLegalDocuments";
181 case AutofillMetrics::AUTHENTICATE_INSTRUMENT:
182 return "AuthenticateInstrument";
183 case AutofillMetrics::GET_FULL_WALLET:
184 return "GetFullWallet";
185 case AutofillMetrics::GET_WALLET_ITEMS:
186 return "GetWalletItems";
187 case AutofillMetrics::SAVE_TO_WALLET:
188 return "SaveToWallet";
189 case AutofillMetrics::UNKNOWN_API_CALL:
190 case AutofillMetrics::NUM_WALLET_API_CALLS:
192 return "UnknownApiCall";
196 return "UnknownApiCall";
199 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
200 // to vary over the program's runtime.
201 void LogUMAHistogramEnumeration(const std::string& name,
203 int boundary_value) {
204 DCHECK_LT(sample, boundary_value);
206 // Note: This leaks memory, which is expected behavior.
207 base::HistogramBase* histogram =
208 base::LinearHistogram::FactoryGet(
213 base::HistogramBase::kUmaTargetedHistogramFlag);
214 histogram->Add(sample);
217 // A version of the UMA_HISTOGRAM_TIMES macro that allows the |name|
218 // to vary over the program's runtime.
219 void LogUMAHistogramTimes(const std::string& name,
220 const base::TimeDelta& duration) {
221 // Note: This leaks memory, which is expected behavior.
222 base::HistogramBase* histogram =
223 base::Histogram::FactoryTimeGet(
225 base::TimeDelta::FromMilliseconds(1),
226 base::TimeDelta::FromSeconds(10),
228 base::HistogramBase::kUmaTargetedHistogramFlag);
229 histogram->AddTime(duration);
232 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name|
233 // to vary over the program's runtime.
234 void LogUMAHistogramLongTimes(const std::string& name,
235 const base::TimeDelta& duration) {
236 // Note: This leaks memory, which is expected behavior.
237 base::HistogramBase* histogram =
238 base::Histogram::FactoryTimeGet(
240 base::TimeDelta::FromMilliseconds(1),
241 base::TimeDelta::FromHours(1),
243 base::HistogramBase::kUmaTargetedHistogramFlag);
244 histogram->AddTime(duration);
247 // Logs a type quality metric. The primary histogram name is constructed based
248 // on |base_name| and |experiment_id|. The field-specific histogram name also
249 // factors in the |field_type|. Logs a sample of |metric|, which should be in
250 // the range [0, |num_possible_metrics|).
251 void LogTypeQualityMetric(const std::string& base_name,
253 const int num_possible_metrics,
254 const ServerFieldType field_type,
255 const std::string& experiment_id) {
256 DCHECK_LT(metric, num_possible_metrics);
258 std::string histogram_name = base_name;
259 if (!experiment_id.empty())
260 histogram_name += "_" + experiment_id;
261 LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics);
263 std::string sub_histogram_name = base_name + ".ByFieldType";
264 if (!experiment_id.empty())
265 sub_histogram_name += "_" + experiment_id;
266 const int field_type_group_metric =
267 GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics);
268 const int num_field_type_group_metrics =
269 num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS;
270 LogUMAHistogramEnumeration(sub_histogram_name,
271 field_type_group_metric,
272 num_field_type_group_metrics);
275 void LogServerExperimentId(const std::string& histogram_name,
276 const std::string& experiment_id) {
277 ServerExperiment metric = UNKNOWN_EXPERIMENT;
279 const std::string default_experiment_name =
280 FormStructure(FormData()).server_experiment_id();
281 if (experiment_id.empty())
282 metric = NO_EXPERIMENT;
283 else if (experiment_id == "ar06")
284 metric = ACCEPTANCE_RATIO_06;
285 else if (experiment_id == "ar1")
286 metric = ACCEPTANCE_RATIO_1;
287 else if (experiment_id == "ar2")
288 metric = ACCEPTANCE_RATIO_2;
289 else if (experiment_id == "ar4")
290 metric = ACCEPTANCE_RATIO_4;
291 else if (experiment_id == "ar05wlr15")
292 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15;
293 else if (experiment_id == "ar05wlr25")
294 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25;
295 else if (experiment_id == "ar05wr15fs5")
296 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5;
297 else if (experiment_id == "tbar1")
298 metric = TOOLBAR_DATA_ONLY;
299 else if (experiment_id == "ar04wr3fs4")
300 metric = ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4;
301 else if (experiment_id == default_experiment_name)
302 metric = NO_SERVER_RESPONSE;
303 else if (experiment_id == "fp05")
304 metric = PROBABILITY_PICKER_05;
305 else if (experiment_id == "fp025")
306 metric = PROBABILITY_PICKER_025;
307 else if (experiment_id == "fp05cc03")
308 metric = PROBABILITY_PICKER_025_CC_THRESHOLD_03;
309 else if (experiment_id == "fp05cco03")
310 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03;
311 else if (experiment_id == "fp05cco03cstd")
312 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK;
313 else if (experiment_id == "fp05cc03e1")
314 metric = PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1;
316 DCHECK_LT(metric, NUM_SERVER_EXPERIMENTS);
317 LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS);
322 AutofillMetrics::AutofillMetrics() {
325 AutofillMetrics::~AutofillMetrics() {
328 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const {
329 DCHECK_LT(metric, NUM_INFO_BAR_METRICS);
331 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
332 NUM_INFO_BAR_METRICS);
335 void AutofillMetrics::LogDialogDismissalState(
336 DialogDismissalState state) const {
337 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
338 state, NUM_DIALOG_DISMISSAL_STATES);
341 void AutofillMetrics::LogDialogInitialUserState(
342 DialogInitialUserStateMetric user_type) const {
343 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
344 user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS);
347 void AutofillMetrics::LogDialogLatencyToShow(
348 const base::TimeDelta& duration) const {
349 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
352 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
353 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
354 event, NUM_DIALOG_POPUP_EVENTS);
357 void AutofillMetrics::LogDialogSecurityMetric(
358 DialogSecurityMetric metric) const {
359 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
360 metric, NUM_DIALOG_SECURITY_METRICS);
363 void AutofillMetrics::LogDialogUiDuration(
364 const base::TimeDelta& duration,
365 DialogDismissalAction dismissal_action) const {
367 switch (dismissal_action) {
368 case DIALOG_ACCEPTED:
372 case DIALOG_CANCELED:
377 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration);
378 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix,
382 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
383 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
384 NUM_DIALOG_UI_EVENTS);
387 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
388 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
389 NUM_WALLET_ERROR_METRICS);
392 void AutofillMetrics::LogWalletApiCallDuration(
393 WalletApiCallMetric metric,
394 const base::TimeDelta& duration) const {
395 LogUMAHistogramTimes("Wallet.ApiCallDuration." +
396 WalletApiMetricToString(metric), duration);
399 void AutofillMetrics::LogWalletMalformedResponseMetric(
400 WalletApiCallMetric metric) const {
401 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
402 NUM_WALLET_API_CALLS);
405 void AutofillMetrics::LogWalletRequiredActionMetric(
406 WalletRequiredActionMetric required_action) const {
407 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
408 required_action, NUM_WALLET_REQUIRED_ACTIONS);
411 void AutofillMetrics::LogWalletResponseCode(int response_code) const {
412 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
415 void AutofillMetrics::LogDeveloperEngagementMetric(
416 DeveloperEngagementMetric metric) const {
417 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS);
419 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric,
420 NUM_DEVELOPER_ENGAGEMENT_METRICS);
423 void AutofillMetrics::LogHeuristicTypePrediction(
424 FieldTypeQualityMetric metric,
425 ServerFieldType field_type,
426 const std::string& experiment_id) const {
427 LogTypeQualityMetric("Autofill.Quality.HeuristicType",
428 metric, NUM_FIELD_TYPE_QUALITY_METRICS,
429 field_type, experiment_id);
432 void AutofillMetrics::LogOverallTypePrediction(
433 FieldTypeQualityMetric metric,
434 ServerFieldType field_type,
435 const std::string& experiment_id) const {
436 LogTypeQualityMetric("Autofill.Quality.PredictedType",
437 metric, NUM_FIELD_TYPE_QUALITY_METRICS,
438 field_type, experiment_id);
441 void AutofillMetrics::LogServerTypePrediction(
442 FieldTypeQualityMetric metric,
443 ServerFieldType field_type,
444 const std::string& experiment_id) const {
445 LogTypeQualityMetric("Autofill.Quality.ServerType",
446 metric, NUM_FIELD_TYPE_QUALITY_METRICS,
447 field_type, experiment_id);
450 void AutofillMetrics::LogQualityMetric(QualityMetric metric,
451 const std::string& experiment_id) const {
452 DCHECK_LT(metric, NUM_QUALITY_METRICS);
454 std::string histogram_name = "Autofill.Quality";
455 if (!experiment_id.empty())
456 histogram_name += "_" + experiment_id;
458 LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS);
461 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const {
462 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS);
464 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
465 NUM_SERVER_QUERY_METRICS);
468 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
469 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS);
471 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
472 NUM_USER_HAPPINESS_METRICS);
475 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
476 const base::TimeDelta& duration) const {
477 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
479 base::TimeDelta::FromMilliseconds(100),
480 base::TimeDelta::FromMinutes(10),
484 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
485 const base::TimeDelta& duration) const {
486 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
488 base::TimeDelta::FromMilliseconds(100),
489 base::TimeDelta::FromMinutes(10),
493 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
494 const base::TimeDelta& duration) const {
495 UMA_HISTOGRAM_CUSTOM_TIMES(
496 "Autofill.FillDuration.FromInteraction.WithAutofill",
498 base::TimeDelta::FromMilliseconds(100),
499 base::TimeDelta::FromMinutes(10),
503 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
504 const base::TimeDelta& duration) const {
505 UMA_HISTOGRAM_CUSTOM_TIMES(
506 "Autofill.FillDuration.FromInteraction.WithoutAutofill",
508 base::TimeDelta::FromMilliseconds(100),
509 base::TimeDelta::FromMinutes(10),
513 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
514 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
517 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
518 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
521 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
522 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
525 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
526 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
529 void AutofillMetrics::LogServerExperimentIdForQuery(
530 const std::string& experiment_id) const {
531 LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id);
534 void AutofillMetrics::LogServerExperimentIdForUpload(
535 const std::string& experiment_id) const {
536 LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id);
539 } // namespace autofill