OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/autofill/autofill_metrics.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/metrics/histogram.h" | |
9 #include "base/time.h" | |
10 #include "chrome/browser/autofill/autofill_type.h" | |
11 #include "chrome/browser/autofill/form_structure.h" | |
12 #include "components/autofill/common/form_data.h" | |
13 | |
14 namespace { | |
15 | |
16 // Server experiments we support. | |
17 enum ServerExperiment { | |
18 NO_EXPERIMENT = 0, | |
19 UNKNOWN_EXPERIMENT, | |
20 ACCEPTANCE_RATIO_06, | |
21 ACCEPTANCE_RATIO_1, | |
22 ACCEPTANCE_RATIO_2, | |
23 ACCEPTANCE_RATIO_4, | |
24 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15, | |
25 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25, | |
26 ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5, | |
27 TOOLBAR_DATA_ONLY, | |
28 ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4, | |
29 NO_SERVER_RESPONSE, | |
30 PROBABILITY_PICKER_05, | |
31 PROBABILITY_PICKER_025, | |
32 PROBABILITY_PICKER_025_CC_THRESHOLD_03, | |
33 PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03, | |
34 PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK, | |
35 PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1, | |
36 NUM_SERVER_EXPERIMENTS | |
37 }; | |
38 | |
39 enum FieldTypeGroupForMetrics { | |
40 AMBIGUOUS = 0, | |
41 NAME, | |
42 COMPANY, | |
43 ADDRESS_LINE_1, | |
44 ADDRESS_LINE_2, | |
45 ADDRESS_CITY, | |
46 ADDRESS_STATE, | |
47 ADDRESS_ZIP, | |
48 ADDRESS_COUNTRY, | |
49 PHONE, | |
50 FAX, // Deprecated. | |
51 EMAIL, | |
52 CREDIT_CARD_NAME, | |
53 CREDIT_CARD_NUMBER, | |
54 CREDIT_CARD_DATE, | |
55 CREDIT_CARD_TYPE, | |
56 NUM_FIELD_TYPE_GROUPS_FOR_METRICS | |
57 }; | |
58 | |
59 // First, translates |field_type| to the corresponding logical |group| from | |
60 // |FieldTypeGroupForMetrics|. Then, interpolates this with the given |metric|, | |
61 // which should be in the range [0, |num_possible_metrics|). | |
62 // Returns the interpolated index. | |
63 // | |
64 // The interpolation maps the pair (|group|, |metric|) to a single index, so | |
65 // that all the indicies for a given group are adjacent. In particular, with | |
66 // the groups {AMBIGUOUS, NAME, ...} combining with the metrics {UNKNOWN, MATCH, | |
67 // MISMATCH}, we create this set of mapped indices: | |
68 // { | |
69 // AMBIGUOUS+UNKNOWN, | |
70 // AMBIGUOUS+MATCH, | |
71 // AMBIGUOUS+MISMATCH, | |
72 // NAME+UNKNOWN, | |
73 // NAME+MATCH, | |
74 // NAME+MISMATCH, | |
75 // ... | |
76 // }. | |
77 // | |
78 // Clients must ensure that |field_type| is one of the types Chrome supports | |
79 // natively, e.g. |field_type| must not be a billng address. | |
80 int GetFieldTypeGroupMetric(const AutofillFieldType field_type, | |
81 const int metric, | |
82 const int num_possible_metrics) { | |
83 DCHECK(metric < num_possible_metrics); | |
84 | |
85 FieldTypeGroupForMetrics group; | |
86 switch (AutofillType(field_type).group()) { | |
87 case AutofillType::NO_GROUP: | |
88 group = AMBIGUOUS; | |
89 break; | |
90 | |
91 case AutofillType::NAME: | |
92 group = NAME; | |
93 break; | |
94 | |
95 case AutofillType::COMPANY: | |
96 group = COMPANY; | |
97 break; | |
98 | |
99 case AutofillType::ADDRESS_HOME: | |
100 switch (field_type) { | |
101 case ADDRESS_HOME_LINE1: | |
102 group = ADDRESS_LINE_1; | |
103 break; | |
104 case ADDRESS_HOME_LINE2: | |
105 group = ADDRESS_LINE_2; | |
106 break; | |
107 case ADDRESS_HOME_CITY: | |
108 group = ADDRESS_CITY; | |
109 break; | |
110 case ADDRESS_HOME_STATE: | |
111 group = ADDRESS_STATE; | |
112 break; | |
113 case ADDRESS_HOME_ZIP: | |
114 group = ADDRESS_ZIP; | |
115 break; | |
116 case ADDRESS_HOME_COUNTRY: | |
117 group = ADDRESS_COUNTRY; | |
118 break; | |
119 default: | |
120 NOTREACHED(); | |
121 group = AMBIGUOUS; | |
122 } | |
123 break; | |
124 | |
125 case AutofillType::EMAIL: | |
126 group = EMAIL; | |
127 break; | |
128 | |
129 case AutofillType::PHONE: | |
130 group = PHONE; | |
131 break; | |
132 | |
133 case AutofillType::CREDIT_CARD: | |
134 switch (field_type) { | |
135 case ::CREDIT_CARD_NAME: | |
136 group = CREDIT_CARD_NAME; | |
137 break; | |
138 case ::CREDIT_CARD_NUMBER: | |
139 group = CREDIT_CARD_NUMBER; | |
140 break; | |
141 case ::CREDIT_CARD_TYPE: | |
142 group = CREDIT_CARD_TYPE; | |
143 default: | |
144 group = CREDIT_CARD_DATE; | |
145 } | |
146 break; | |
147 | |
148 default: | |
149 NOTREACHED(); | |
150 group = AMBIGUOUS; | |
151 } | |
152 | |
153 // Interpolate the |metric| with the |group|, so that all metrics for a given | |
154 // |group| are adjacent. | |
155 return (group * num_possible_metrics) + metric; | |
156 } | |
157 | |
158 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| | |
159 // to vary over the program's runtime. | |
160 void LogUMAHistogramEnumeration(const std::string& name, | |
161 int sample, | |
162 int boundary_value) { | |
163 // Note: This leaks memory, which is expected behavior. | |
164 base::HistogramBase* histogram = | |
165 base::LinearHistogram::FactoryGet( | |
166 name, | |
167 1, | |
168 boundary_value, | |
169 boundary_value + 1, | |
170 base::HistogramBase::kUmaTargetedHistogramFlag); | |
171 histogram->Add(sample); | |
172 } | |
173 | |
174 // A version of the UMA_HISTOGRAM_LONG_TIMES macro that allows the |name| | |
175 // to vary over the program's runtime. | |
176 void LogUMAHistogramLongTimes(const std::string& name, | |
177 const base::TimeDelta& duration) { | |
178 // Note: This leaks memory, which is expected behavior. | |
179 base::HistogramBase* histogram = | |
180 base::Histogram::FactoryTimeGet( | |
181 name, | |
182 base::TimeDelta::FromMilliseconds(1), | |
183 base::TimeDelta::FromHours(1), | |
184 50, | |
185 base::HistogramBase::kUmaTargetedHistogramFlag); | |
186 histogram->AddTime(duration); | |
187 } | |
188 | |
189 // Logs a type quality metric. The primary histogram name is constructed based | |
190 // on |base_name| and |experiment_id|. The field-specific histogram name also | |
191 // factors in the |field_type|. Logs a sample of |metric|, which should be in | |
192 // the range [0, |num_possible_metrics|). | |
193 void LogTypeQualityMetric(const std::string& base_name, | |
194 const int metric, | |
195 const int num_possible_metrics, | |
196 const AutofillFieldType field_type, | |
197 const std::string& experiment_id) { | |
198 DCHECK(metric < num_possible_metrics); | |
199 | |
200 std::string histogram_name = base_name; | |
201 if (!experiment_id.empty()) | |
202 histogram_name += "_" + experiment_id; | |
203 LogUMAHistogramEnumeration(histogram_name, metric, num_possible_metrics); | |
204 | |
205 std::string sub_histogram_name = base_name + ".ByFieldType"; | |
206 if (!experiment_id.empty()) | |
207 sub_histogram_name += "_" + experiment_id; | |
208 const int field_type_group_metric = | |
209 GetFieldTypeGroupMetric(field_type, metric, num_possible_metrics); | |
210 const int num_field_type_group_metrics = | |
211 num_possible_metrics * NUM_FIELD_TYPE_GROUPS_FOR_METRICS; | |
212 LogUMAHistogramEnumeration(sub_histogram_name, | |
213 field_type_group_metric, | |
214 num_field_type_group_metrics); | |
215 } | |
216 | |
217 void LogServerExperimentId(const std::string& histogram_name, | |
218 const std::string& experiment_id) { | |
219 ServerExperiment metric = UNKNOWN_EXPERIMENT; | |
220 | |
221 const std::string default_experiment_name = | |
222 FormStructure(FormData(), std::string()).server_experiment_id(); | |
223 if (experiment_id.empty()) | |
224 metric = NO_EXPERIMENT; | |
225 else if (experiment_id == "ar06") | |
226 metric = ACCEPTANCE_RATIO_06; | |
227 else if (experiment_id == "ar1") | |
228 metric = ACCEPTANCE_RATIO_1; | |
229 else if (experiment_id == "ar2") | |
230 metric = ACCEPTANCE_RATIO_2; | |
231 else if (experiment_id == "ar4") | |
232 metric = ACCEPTANCE_RATIO_4; | |
233 else if (experiment_id == "ar05wlr15") | |
234 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15; | |
235 else if (experiment_id == "ar05wlr25") | |
236 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_25; | |
237 else if (experiment_id == "ar05wr15fs5") | |
238 metric = ACCEPTANCE_RATIO_05_WINNER_LEAD_RATIO_15_MIN_FORM_SCORE_5; | |
239 else if (experiment_id == "tbar1") | |
240 metric = TOOLBAR_DATA_ONLY; | |
241 else if (experiment_id == "ar04wr3fs4") | |
242 metric = ACCEPTANCE_RATIO_04_WINNER_LEAD_RATIO_3_MIN_FORM_SCORE_4; | |
243 else if (experiment_id == default_experiment_name) | |
244 metric = NO_SERVER_RESPONSE; | |
245 else if (experiment_id == "fp05") | |
246 metric = PROBABILITY_PICKER_05; | |
247 else if (experiment_id == "fp025") | |
248 metric = PROBABILITY_PICKER_025; | |
249 else if (experiment_id == "fp05cc03") | |
250 metric = PROBABILITY_PICKER_025_CC_THRESHOLD_03; | |
251 else if (experiment_id == "fp05cco03") | |
252 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03; | |
253 else if (experiment_id == "fp05cco03cstd") | |
254 metric = PROBABILITY_PICKER_025_CONTEXTUAL_CC_THRESHOLD_03_WITH_FALLBACK; | |
255 else if (experiment_id == "fp05cc03e1") | |
256 metric = PROBABILITY_PICKER_05_CC_NAME_THRESHOLD_03_EXPERIMENT_1; | |
257 | |
258 DCHECK(metric < NUM_SERVER_EXPERIMENTS); | |
259 LogUMAHistogramEnumeration(histogram_name, metric, NUM_SERVER_EXPERIMENTS); | |
260 } | |
261 | |
262 } // namespace | |
263 | |
264 AutofillMetrics::AutofillMetrics() { | |
265 } | |
266 | |
267 AutofillMetrics::~AutofillMetrics() { | |
268 } | |
269 | |
270 void AutofillMetrics::LogAutocheckoutBubbleMetric(BubbleMetric metric) const { | |
271 DCHECK(metric < NUM_BUBBLE_METRICS); | |
272 | |
273 UMA_HISTOGRAM_ENUMERATION("Autocheckout.Bubble", metric, NUM_BUBBLE_METRICS); | |
274 } | |
275 | |
276 void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) const { | |
277 DCHECK(metric < NUM_INFO_BAR_METRICS); | |
278 | |
279 UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric, | |
280 NUM_INFO_BAR_METRICS); | |
281 } | |
282 | |
283 void AutofillMetrics::LogRequestAutocompleteUiDuration( | |
284 const base::TimeDelta& duration, | |
285 autofill::DialogType dialog_type, | |
286 DialogDismissalAction dismissal_action) const { | |
287 std::string prefix; | |
288 switch (dialog_type) { | |
289 case autofill::DIALOG_TYPE_AUTOCHECKOUT: | |
290 prefix = "Autocheckout"; | |
291 break; | |
292 | |
293 case autofill::DIALOG_TYPE_REQUEST_AUTOCOMPLETE: | |
294 prefix = "RequestAutocomplete"; | |
295 break; | |
296 } | |
297 | |
298 std::string suffix; | |
299 switch (dismissal_action) { | |
300 case DIALOG_ACCEPTED: | |
301 suffix = "Submit"; | |
302 break; | |
303 | |
304 case DIALOG_CANCELED: | |
305 suffix = "Cancel"; | |
306 break; | |
307 } | |
308 | |
309 LogUMAHistogramLongTimes(prefix + ".UiDuration", duration); | |
310 LogUMAHistogramLongTimes(prefix + ".UiDuration." + suffix, duration); | |
311 } | |
312 | |
313 void AutofillMetrics::LogAutocheckoutDuration( | |
314 const base::TimeDelta& duration, | |
315 AutocheckoutCompletionStatus status) const { | |
316 std::string suffix; | |
317 switch (status) { | |
318 case AUTOCHECKOUT_FAILED: | |
319 suffix = "Failed"; | |
320 break; | |
321 | |
322 case AUTOCHECKOUT_SUCCEEDED: | |
323 suffix = "Succeeded"; | |
324 break; | |
325 } | |
326 | |
327 LogUMAHistogramLongTimes("Autocheckout.FlowDuration", duration); | |
328 LogUMAHistogramLongTimes("Autocheckout.FlowDuration." + suffix, duration); | |
329 } | |
330 | |
331 void AutofillMetrics::LogDeveloperEngagementMetric( | |
332 DeveloperEngagementMetric metric) const { | |
333 DCHECK(metric < NUM_DEVELOPER_ENGAGEMENT_METRICS); | |
334 | |
335 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, | |
336 NUM_DEVELOPER_ENGAGEMENT_METRICS); | |
337 } | |
338 | |
339 void AutofillMetrics::LogHeuristicTypePrediction( | |
340 FieldTypeQualityMetric metric, | |
341 AutofillFieldType field_type, | |
342 const std::string& experiment_id) const { | |
343 LogTypeQualityMetric("Autofill.Quality.HeuristicType", | |
344 metric, NUM_FIELD_TYPE_QUALITY_METRICS, | |
345 field_type, experiment_id); | |
346 } | |
347 | |
348 void AutofillMetrics::LogOverallTypePrediction( | |
349 FieldTypeQualityMetric metric, | |
350 AutofillFieldType field_type, | |
351 const std::string& experiment_id) const { | |
352 LogTypeQualityMetric("Autofill.Quality.PredictedType", | |
353 metric, NUM_FIELD_TYPE_QUALITY_METRICS, | |
354 field_type, experiment_id); | |
355 } | |
356 | |
357 void AutofillMetrics::LogServerTypePrediction( | |
358 FieldTypeQualityMetric metric, | |
359 AutofillFieldType field_type, | |
360 const std::string& experiment_id) const { | |
361 LogTypeQualityMetric("Autofill.Quality.ServerType", | |
362 metric, NUM_FIELD_TYPE_QUALITY_METRICS, | |
363 field_type, experiment_id); | |
364 } | |
365 | |
366 void AutofillMetrics::LogQualityMetric(QualityMetric metric, | |
367 const std::string& experiment_id) const { | |
368 DCHECK(metric < NUM_QUALITY_METRICS); | |
369 | |
370 std::string histogram_name = "Autofill.Quality"; | |
371 if (!experiment_id.empty()) | |
372 histogram_name += "_" + experiment_id; | |
373 | |
374 LogUMAHistogramEnumeration(histogram_name, metric, NUM_QUALITY_METRICS); | |
375 } | |
376 | |
377 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const { | |
378 DCHECK(metric < NUM_SERVER_QUERY_METRICS); | |
379 | |
380 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, | |
381 NUM_SERVER_QUERY_METRICS); | |
382 } | |
383 | |
384 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const { | |
385 DCHECK(metric < NUM_USER_HAPPINESS_METRICS); | |
386 | |
387 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, | |
388 NUM_USER_HAPPINESS_METRICS); | |
389 } | |
390 | |
391 void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill( | |
392 const base::TimeDelta& duration) const { | |
393 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill", | |
394 duration, | |
395 base::TimeDelta::FromMilliseconds(100), | |
396 base::TimeDelta::FromMinutes(10), | |
397 50); | |
398 } | |
399 | |
400 void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill( | |
401 const base::TimeDelta& duration) const { | |
402 UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill", | |
403 duration, | |
404 base::TimeDelta::FromMilliseconds(100), | |
405 base::TimeDelta::FromMinutes(10), | |
406 50); | |
407 } | |
408 | |
409 void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( | |
410 const base::TimeDelta& duration) const { | |
411 UMA_HISTOGRAM_CUSTOM_TIMES( | |
412 "Autofill.FillDuration.FromInteraction.WithAutofill", | |
413 duration, | |
414 base::TimeDelta::FromMilliseconds(100), | |
415 base::TimeDelta::FromMinutes(10), | |
416 50); | |
417 } | |
418 | |
419 void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( | |
420 const base::TimeDelta& duration) const { | |
421 UMA_HISTOGRAM_CUSTOM_TIMES( | |
422 "Autofill.FillDuration.FromInteraction.WithoutAutofill", | |
423 duration, | |
424 base::TimeDelta::FromMilliseconds(100), | |
425 base::TimeDelta::FromMinutes(10), | |
426 50); | |
427 } | |
428 | |
429 void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const { | |
430 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled); | |
431 } | |
432 | |
433 void AutofillMetrics::LogIsAutofillEnabledAtPageLoad(bool enabled) const { | |
434 UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.PageLoad", enabled); | |
435 } | |
436 | |
437 void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const { | |
438 UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles); | |
439 } | |
440 | |
441 void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const { | |
442 UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions); | |
443 } | |
444 | |
445 void AutofillMetrics::LogServerExperimentIdForQuery( | |
446 const std::string& experiment_id) const { | |
447 LogServerExperimentId("Autofill.ServerExperimentId.Query", experiment_id); | |
448 } | |
449 | |
450 void AutofillMetrics::LogServerExperimentIdForUpload( | |
451 const std::string& experiment_id) const { | |
452 LogServerExperimentId("Autofill.ServerExperimentId.Upload", experiment_id); | |
453 } | |
OLD | NEW |