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