- add sources.
[platform/framework/web/crosswalk.git] / src / components / autofill / core / browser / autofill_metrics.cc
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 // Server experiments we support.
20 enum 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
42 enum 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.
84 int 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
176 std::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.
201 void 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.
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(
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.
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(
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|).
251 void 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
275 void 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
322 AutofillMetrics::AutofillMetrics() {
323 }
324
325 AutofillMetrics::~AutofillMetrics() {
326 }
327
328 void 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
335 void AutofillMetrics::LogDialogDismissalState(
336     DialogDismissalState state) const {
337   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.DismissalState",
338                             state, NUM_DIALOG_DISMISSAL_STATES);
339 }
340
341 void AutofillMetrics::LogDialogInitialUserState(
342     DialogInitialUserStateMetric user_type) const {
343   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.InitialUserState",
344                             user_type, NUM_DIALOG_INITIAL_USER_STATE_METRICS);
345 }
346
347 void AutofillMetrics::LogDialogLatencyToShow(
348     const base::TimeDelta& duration) const {
349   LogUMAHistogramTimes("RequestAutocomplete.UiLatencyToShow", duration);
350 }
351
352 void AutofillMetrics::LogDialogPopupEvent(DialogPopupEvent event) const {
353   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.PopupInDialog",
354                             event, NUM_DIALOG_POPUP_EVENTS);
355 }
356
357 void AutofillMetrics::LogDialogSecurityMetric(
358     DialogSecurityMetric metric) const {
359   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.Security",
360                             metric, NUM_DIALOG_SECURITY_METRICS);
361 }
362
363 void 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
382 void AutofillMetrics::LogDialogUiEvent(DialogUiEvent event) const {
383   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.UiEvents", event,
384                             NUM_DIALOG_UI_EVENTS);
385 }
386
387 void AutofillMetrics::LogWalletErrorMetric(WalletErrorMetric metric) const {
388   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletErrors", metric,
389                             NUM_WALLET_ERROR_METRICS);
390 }
391
392 void AutofillMetrics::LogWalletApiCallDuration(
393     WalletApiCallMetric metric,
394     const base::TimeDelta& duration) const {
395   LogUMAHistogramTimes("Wallet.ApiCallDuration." +
396                        WalletApiMetricToString(metric), duration);
397 }
398
399 void AutofillMetrics::LogWalletMalformedResponseMetric(
400     WalletApiCallMetric metric) const {
401   UMA_HISTOGRAM_ENUMERATION("Wallet.MalformedResponse", metric,
402                             NUM_WALLET_API_CALLS);
403 }
404
405 void AutofillMetrics::LogWalletRequiredActionMetric(
406       WalletRequiredActionMetric required_action) const {
407   UMA_HISTOGRAM_ENUMERATION("RequestAutocomplete.WalletRequiredActions",
408                             required_action, NUM_WALLET_REQUIRED_ACTIONS);
409 }
410
411 void AutofillMetrics::LogWalletResponseCode(int response_code) const {
412   UMA_HISTOGRAM_SPARSE_SLOWLY("Wallet.ResponseCode", response_code);
413 }
414
415 void 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
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);
430 }
431
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);
439 }
440
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);
448 }
449
450 void 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
461 void 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
468 void 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
475 void 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
484 void 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
493 void 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
503 void 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
513 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
514   UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
515 }
516
517 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const {
518   UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled);
519 }
520
521 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
522   UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
523 }
524
525 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
526   UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
527 }
528
529 void AutofillMetrics::LogServerExperimentIdForQuery(
530     const std::string& experiment_id) const {
531   LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id);
532 }
533
534 void AutofillMetrics::LogServerExperimentIdForUpload(
535     const std::string& experiment_id) const {
536   LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id);
537 }
538
539 }  // namespace autofill