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