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     case ::autofill::TRANSACTION:
    152       NOTREACHED();
    153       break;
    154   }
    155 
    156   // Interpolate the |metric| with the |group|, so that all metrics for a given
    157   // |group| are adjacent.
    158   return (group * num_possible_metrics) + metric;
    159 }
    160 
    161 std::string WalletApiMetricToString(
    162     AutofillMetrics::WalletApiCallMetric metric) {
    163   switch (metric) {
    164     case AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS:
    165       return "AcceptLegalDocuments";
    166     case AutofillMetrics::AUTHENTICATE_INSTRUMENT:
    167       return "AuthenticateInstrument";
    168     case AutofillMetrics::GET_FULL_WALLET:
    169       return "GetFullWallet";
    170     case AutofillMetrics::GET_WALLET_ITEMS:
    171       return "GetWalletItems";
    172     case AutofillMetrics::SAVE_TO_WALLET:
    173       return "SaveToWallet";
    174     case AutofillMetrics::UNKNOWN_API_CALL:
    175     case AutofillMetrics::NUM_WALLET_API_CALLS:
    176       NOTREACHED();
    177       return "UnknownApiCall";
    178   }
    179 
    180   NOTREACHED();
    181   return "UnknownApiCall";
    182 }
    183 
    184 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
    185 // to vary over the program's runtime.
    186 void LogUMAHistogramEnumeration(const std::string& name,
    187                                 int sample,
    188                                 int boundary_value) {
    189   DCHECK_LT(sample, boundary_value);
    190 
    191   // Note: This leaks memory, which is expected behavior.
    192   base::HistogramBase* histogram =
    193       base::LinearHistogram::FactoryGet(
    194           name,
    195           1,
    196           boundary_value,
    197           boundary_value + 1,
    198           base::HistogramBase::kUmaTargetedHistogramFlag);
    199   histogram->Add(sample);
    200 }
    201 
    202 // A version of the UMA_HISTOGRAM_TIMES macro that allows the |name|
    203 // to vary over the program's runtime.
    204 void LogUMAHistogramTimes(const std::string& name,
    205                           const base::TimeDelta& duration) {
    206   // Note: This leaks memory, which is expected behavior.
    207   base::HistogramBase* histogram =
    208       base::Histogram::FactoryTimeGet(
    209           name,
    210           base::TimeDelta::FromMilliseconds(1),
    211           base::TimeDelta::FromSeconds(10),
    212           50,
    213           base::HistogramBase::kUmaTargetedHistogramFlag);
    214   histogram->AddTime(duration);
    215 }
    216 
    217 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name|
    218 // to vary over the program's runtime.
    219 void LogUMAHistogramLongTimes(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::FromHours(1),
    227           50,
    228           base::HistogramBase::kUmaTargetedHistogramFlag);
    229   histogram->AddTime(duration);
    230 }
    231 
    232 // Logs a type quality metric.  The primary histogram name is constructed based
    233 // on |base_name|.  The field-specific histogram name also factors in the
    234 // |field_type|.  Logs a sample of |metric|, which should be in the range
    235 // [0, |num_possible_metrics|).
    236 void LogTypeQualityMetric(const std::string& base_name,
    237                           const int metric,
    238                           const int num_possible_metrics,
    239                           const ServerFieldType field_type) {
    240   DCHECK_LT(metric, num_possible_metrics);
    241 
    242   std::string histogram_name = base_name;
    243   LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics);
    244 
    245   std::string sub_histogram_name = base_name + ".ByFieldType";
    246   const int field_type_group_metric =
    247       GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics);
    248   const int num_field_type_group_metrics =
    249       num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS;
    250   LogUMAHistogramEnumeration(sub_histogram_name,
    251                              field_type_group_metric,
    252                              num_field_type_group_metrics);
    253 }
    254 
    255 }  // namespace
    256 
    257 AutofillMetrics::AutofillMetrics() {
    258 }
    259 
    260 AutofillMetrics::~AutofillMetrics() {
    261 }
    262 
    263 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const {
    264   DCHECK_LT(metric, NUM_INFO_BAR_METRICS);
    265 
    266   UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
    267                             NUM_INFO_BAR_METRICS);
    268 }
    269 
    270 void AutofillMetrics::LogDialogDismissalState(
    271     DialogDismissalState state) const {
    272   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
    273                             state, NUM_DIALOG_DISMISSAL_STATES);
    274 }
    275 
    276 void AutofillMetrics::LogDialogInitialUserState(
    277     DialogInitialUserStateMetric user_type) const {
    278   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
    279                             user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS);
    280 }
    281 
    282 void AutofillMetrics::LogDialogLatencyToShow(
    283     const base::TimeDelta& duration) const {
    284   LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
    285 }
    286 
    287 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
    288   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
    289                             event, NUM_DIALOG_POPUP_EVENTS);
    290 }
    291 
    292 void AutofillMetrics::LogDialogSecurityMetric(
    293     DialogSecurityMetric metric) const {
    294   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
    295                             metric, NUM_DIALOG_SECURITY_METRICS);
    296 }
    297 
    298 void AutofillMetrics::LogDialogUiDuration(
    299     const base::TimeDelta& duration,
    300     DialogDismissalAction dismissal_action) const {
    301   std::string suffix;
    302   switch (dismissal_action) {
    303     case DIALOG_ACCEPTED:
    304       suffix = "Submit";
    305       break;
    306 
    307     case DIALOG_CANCELED:
    308       suffix = "Cancel";
    309       break;
    310   }
    311 
    312   LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration", duration);
    313   LogUMAHistogramLongTimes("RequestAutocomplete.UiDuration." + suffix,
    314                            duration);
    315 }
    316 
    317 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
    318   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
    319                             NUM_DIALOG_UI_EVENTS);
    320 }
    321 
    322 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
    323   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
    324                             NUM_WALLET_ERROR_METRICS);
    325 }
    326 
    327 void AutofillMetrics::LogWalletApiCallDuration(
    328     WalletApiCallMetric metric,
    329     const base::TimeDelta& duration) const {
    330   LogUMAHistogramTimes("Wallet.ApiCallDuration." +
    331                        WalletApiMetricToString(metric), duration);
    332 }
    333 
    334 void AutofillMetrics::LogWalletMalformedResponseMetric(
    335     WalletApiCallMetric metric) const {
    336   UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
    337                             NUM_WALLET_API_CALLS);
    338 }
    339 
    340 void AutofillMetrics::LogWalletRequiredActionMetric(
    341       WalletRequiredActionMetric required_action) const {
    342   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
    343                             required_action, NUM_WALLET_REQUIRED_ACTIONS);
    344 }
    345 
    346 void AutofillMetrics::LogWalletResponseCode(int response_code) const {
    347   UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
    348 }
    349 
    350 void AutofillMetrics::LogDeveloperEngagementMetric(
    351     DeveloperEngagementMetric metric) const {
    352   DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS);
    353 
    354   UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric,
    355                             NUM_DEVELOPER_ENGAGEMENT_METRICS);
    356 }
    357 
    358 void AutofillMetrics::LogHeuristicTypePrediction(
    359     FieldTypeQualityMetric metric,
    360     ServerFieldType field_type) const {
    361   LogTypeQualityMetric("Autofill.Quality.HeuristicType",
    362                        metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type);
    363 }
    364 
    365 void AutofillMetrics::LogOverallTypePrediction(
    366     FieldTypeQualityMetric metric,
    367     ServerFieldType field_type) const {
    368   LogTypeQualityMetric("Autofill.Quality.PredictedType",
    369                        metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type);
    370 }
    371 
    372 void AutofillMetrics::LogServerTypePrediction(
    373     FieldTypeQualityMetric metric,
    374     ServerFieldType field_type) const {
    375   LogTypeQualityMetric("Autofill.Quality.ServerType",
    376                        metric, NUM_FIELD_TYPE_QUALITY_METRICS, field_type);
    377 }
    378 
    379 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const {
    380   DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS);
    381 
    382   UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
    383                             NUM_SERVER_QUERY_METRICS);
    384 }
    385 
    386 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
    387   DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS);
    388 
    389   UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
    390                             NUM_USER_HAPPINESS_METRICS);
    391 }
    392 
    393 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
    394     const base::TimeDelta& duration) const {
    395   UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
    396                              duration,
    397                              base::TimeDelta::FromMilliseconds(100),
    398                              base::TimeDelta::FromMinutes(10),
    399                              50);
    400 }
    401 
    402 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
    403     const base::TimeDelta& duration) const {
    404   UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
    405                              duration,
    406                              base::TimeDelta::FromMilliseconds(100),
    407                              base::TimeDelta::FromMinutes(10),
    408                              50);
    409 }
    410 
    411 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
    412     const base::TimeDelta& duration) const {
    413   UMA_HISTOGRAM_CUSTOM_TIMES(
    414       "Autofill.FillDuration.FromInteraction.WithAutofill",
    415       duration,
    416       base::TimeDelta::FromMilliseconds(100),
    417       base::TimeDelta::FromMinutes(10),
    418       50);
    419 }
    420 
    421 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
    422     const base::TimeDelta& duration) const {
    423   UMA_HISTOGRAM_CUSTOM_TIMES(
    424        "Autofill.FillDuration.FromInteraction.WithoutAutofill",
    425        duration,
    426        base::TimeDelta::FromMilliseconds(100),
    427        base::TimeDelta::FromMinutes(10),
    428        50);
    429 }
    430 
    431 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
    432   UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
    433 }
    434 
    435 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
    436   UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
    437 }
    438 
    439 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
    440   UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
    441 }
    442 
    443 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
    444   UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
    445 }
    446 
    447 }  // namespace autofill
    448