autofill_metrics.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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 PASSWORD, 60 NUM_FIELD_TYPE_GROUPS_FOR_METRICS 61}; 62 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. 67// 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: 72// { 73// AMBIGUOUS+UNKNOWN, 74// AMBIGUOUS+MATCH, 75// AMBIGUOUS+MISMATCH, 76// NAME+UNKNOWN, 77// NAME+MATCH, 78// NAME+MISMATCH, 79// ... 80// }. 81// 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. 84int GetFieldTypeGroupMetric(const ServerFieldType field_type, 85 const int metric, 86 const int num_possible_metrics) { 87 DCHECK_LT(metric, num_possible_metrics); 88 89 FieldTypeGroupForMetrics group = AMBIGUOUS; 90 switch (AutofillType(field_type).group()) { 91 case ::autofill::NO_GROUP: 92 group = AMBIGUOUS; 93 break; 94 95 case ::autofill::NAME: 96 case ::autofill::NAME_BILLING: 97 group = NAME; 98 break; 99 100 case ::autofill::COMPANY: 101 group = COMPANY; 102 break; 103 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; 109 break; 110 case ADDRESS_HOME_LINE2: 111 group = ADDRESS_LINE_2; 112 break; 113 case ADDRESS_HOME_CITY: 114 group = ADDRESS_CITY; 115 break; 116 case ADDRESS_HOME_STATE: 117 group = ADDRESS_STATE; 118 break; 119 case ADDRESS_HOME_ZIP: 120 group = ADDRESS_ZIP; 121 break; 122 case ADDRESS_HOME_COUNTRY: 123 group = ADDRESS_COUNTRY; 124 break; 125 default: 126 NOTREACHED(); 127 group = AMBIGUOUS; 128 break; 129 } 130 break; 131 132 case ::autofill::EMAIL: 133 group = EMAIL; 134 break; 135 136 case ::autofill::PHONE_HOME: 137 case ::autofill::PHONE_BILLING: 138 group = PHONE; 139 break; 140 141 case ::autofill::CREDIT_CARD: 142 switch (field_type) { 143 case ::autofill::CREDIT_CARD_NAME: 144 group = CREDIT_CARD_NAME; 145 break; 146 case ::autofill::CREDIT_CARD_NUMBER: 147 group = CREDIT_CARD_NUMBER; 148 break; 149 case ::autofill::CREDIT_CARD_TYPE: 150 group = CREDIT_CARD_TYPE; 151 break; 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; 158 break; 159 default: 160 NOTREACHED(); 161 group = AMBIGUOUS; 162 break; 163 } 164 break; 165 166 case ::autofill::PASSWORD_FIELD: 167 group = PASSWORD; 168 break; 169 } 170 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; 174} 175 176std::string WalletApiMetricToString( 177 AutofillMetrics::WalletApiCallMetric metric) { 178 switch (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: 191 NOTREACHED(); 192 return "UnknownApiCall"; 193 } 194 195 NOTREACHED(); 196 return "UnknownApiCall"; 197} 198 199// A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| 200// to vary over the program's runtime. 201void LogUMAHistogramEnumeration(const std::string& name, 202 int sample, 203 int boundary_value) { 204 DCHECK_LT(sample, boundary_value); 205 206 // Note: This leaks memory, which is expected behavior. 207 base::HistogramBase* histogram = 208 base::LinearHistogram::FactoryGet( 209 name, 210 1, 211 boundary_value, 212 boundary_value + 1, 213 base::HistogramBase::kUmaTargetedHistogramFlag); 214 histogram->Add(sample); 215} 216 217// A version of the UMA_HISTOGRAM_TIMES macro that allows the |name| 218// to vary over the program's runtime. 219void 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( 224 name, 225 base::TimeDelta::FromMilliseconds(1), 226 base::TimeDelta::FromSeconds(10), 227 50, 228 base::HistogramBase::kUmaTargetedHistogramFlag); 229 histogram->AddTime(duration); 230} 231 232// A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name| 233// to vary over the program's runtime. 234void 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( 239 name, 240 base::TimeDelta::FromMilliseconds(1), 241 base::TimeDelta::FromHours(1), 242 50, 243 base::HistogramBase::kUmaTargetedHistogramFlag); 244 histogram->AddTime(duration); 245} 246 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|). 251void LogTypeQualityMetric(const std::string& base_name, 252 const int metric, 253 const int num_possible_metrics, 254 const ServerFieldType field_type, 255 const std::string& experiment_id) { 256 DCHECK_LT(metric, num_possible_metrics); 257 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); 262 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); 273} 274 275void LogServerExperimentId(const std::string& histogram_name, 276 const std::string& experiment_id) { 277 ServerExperiment metric = UNKNOWN_EXPERIMENT; 278 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; 315 316 DCHECK_LT(metric, NUM_SERVER_EXPERIMENTS); 317 LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS); 318} 319 320} // namespace 321 322AutofillMetrics::AutofillMetrics() { 323} 324 325AutofillMetrics::~AutofillMetrics() { 326} 327 328void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const { 329 DCHECK_LT(metric, NUM_INFO_BAR_METRICS); 330 331 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric, 332 NUM_INFO_BAR_METRICS); 333} 334 335void AutofillMetrics::LogDialogDismissalState( 336 DialogDismissalState state) const { 337 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState", 338 state, NUM_DIALOG_DISMISSAL_STATES); 339} 340 341void AutofillMetrics::LogDialogInitialUserState( 342 DialogInitialUserStateMetric user_type) const { 343 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState", 344 user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS); 345} 346 347void AutofillMetrics::LogDialogLatencyToShow( 348 const base::TimeDelta& duration) const { 349 LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration); 350} 351 352void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const { 353 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog", 354 event, NUM_DIALOG_POPUP_EVENTS); 355} 356 357void AutofillMetrics::LogDialogSecurityMetric( 358 DialogSecurityMetric metric) const { 359 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security", 360 metric, NUM_DIALOG_SECURITY_METRICS); 361} 362 363void AutofillMetrics::LogDialogUiDuration( 364 const base::TimeDelta& duration, 365 DialogDismissalAction dismissal_action) const { 366 std::string suffix; 367 switch (dismissal_action) { 368 case DIALOG_ACCEPTED: 369 suffix = "Submit"; 370 break; 371 372 case DIALOG_CANCELED: 373 suffix = "Cancel"; 374 break; 375 } 376 377 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration); 378 LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix, 379 duration); 380} 381 382void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const { 383 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event, 384 NUM_DIALOG_UI_EVENTS); 385} 386 387void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const { 388 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric, 389 NUM_WALLET_ERROR_METRICS); 390} 391 392void AutofillMetrics::LogWalletApiCallDuration( 393 WalletApiCallMetric metric, 394 const base::TimeDelta& duration) const { 395 LogUMAHistogramTimes("Wallet.ApiCallDuration." + 396 WalletApiMetricToString(metric), duration); 397} 398 399void AutofillMetrics::LogWalletMalformedResponseMetric( 400 WalletApiCallMetric metric) const { 401 UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric, 402 NUM_WALLET_API_CALLS); 403} 404 405void AutofillMetrics::LogWalletRequiredActionMetric( 406 WalletRequiredActionMetric required_action) const { 407 UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions", 408 required_action, NUM_WALLET_REQUIRED_ACTIONS); 409} 410 411void AutofillMetrics::LogWalletResponseCode(int response_code) const { 412 UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code); 413} 414 415void AutofillMetrics::LogDeveloperEngagementMetric( 416 DeveloperEngagementMetric metric) const { 417 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); 418 419 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, 420 NUM_DEVELOPER_ENGAGEMENT_METRICS); 421} 422 423void 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); 430} 431 432void 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); 439} 440 441void 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); 448} 449 450void AutofillMetrics::LogQualityMetric(QualityMetric metric, 451 const std::string& experiment_id) const { 452 DCHECK_LT(metric, NUM_QUALITY_METRICS); 453 454 std::string histogram_name = "Autofill.Quality"; 455 if (!experiment_id.empty()) 456 histogram_name += "_" + experiment_id; 457 458 LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS); 459} 460 461void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const { 462 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); 463 464 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, 465 NUM_SERVER_QUERY_METRICS); 466} 467 468void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const { 469 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS); 470 471 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, 472 NUM_USER_HAPPINESS_METRICS); 473} 474 475void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill( 476 const base::TimeDelta& duration) const { 477 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill", 478 duration, 479 base::TimeDelta::FromMilliseconds(100), 480 base::TimeDelta::FromMinutes(10), 481 50); 482} 483 484void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill( 485 const base::TimeDelta& duration) const { 486 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill", 487 duration, 488 base::TimeDelta::FromMilliseconds(100), 489 base::TimeDelta::FromMinutes(10), 490 50); 491} 492 493void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( 494 const base::TimeDelta& duration) const { 495 UMA_HISTOGRAM_CUSTOM_TIMES( 496 "Autofill.FillDuration.FromInteraction.WithAutofill", 497 duration, 498 base::TimeDelta::FromMilliseconds(100), 499 base::TimeDelta::FromMinutes(10), 500 50); 501} 502 503void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( 504 const base::TimeDelta& duration) const { 505 UMA_HISTOGRAM_CUSTOM_TIMES( 506 "Autofill.FillDuration.FromInteraction.WithoutAutofill", 507 duration, 508 base::TimeDelta::FromMilliseconds(100), 509 base::TimeDelta::FromMinutes(10), 510 50); 511} 512 513void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const { 514 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled); 515} 516 517void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const { 518 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled); 519} 520 521void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const { 522 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles); 523} 524 525void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const { 526 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions); 527} 528 529void AutofillMetrics::LogServerExperimentIdForQuery( 530 const std::string& experiment_id) const { 531 LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id); 532} 533 534void AutofillMetrics::LogServerExperimentIdForUpload( 535 const std::string& experiment_id) const { 536 LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id); 537} 538 539} // namespace autofill 540