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 "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/search/most_visited_iframe_source.h"
11 #include "chrome/browser/search/search.h"
12 #include "chrome/common/search_urls.h"
13 #include "chrome/common/url_constants.h"
14 #include "content/public/browser/navigation_details.h"
15 #include "content/public/browser/navigation_entry.h"
16 #include "content/public/browser/web_contents.h"
17
18 namespace {
19
20 // Used to track if suggestions were issued by the client or the server.
21 enum SuggestionsType {
22 CLIENT_SIDE = 0,
23 SERVER_SIDE = 1,
24 SUGGESTIONS_TYPE_COUNT = 2
25 };
26
27 // Format string to generate the name for the histogram keeping track of
28 // suggestion impressions.
29 const char kImpressionHistogramWithProvider[] =
30 "NewTabPage.SuggestionsImpression.%s";
31
32 } // namespace
33
34 DEFINE_WEB_CONTENTS_USER_DATA_KEY(NTPUserDataLogger);
35
~NTPUserDataLogger()36 NTPUserDataLogger::~NTPUserDataLogger() {}
37
38 // static
GetOrCreateFromWebContents(content::WebContents * content)39 NTPUserDataLogger* NTPUserDataLogger::GetOrCreateFromWebContents(
40 content::WebContents* content) {
41 // Calling CreateForWebContents when an instance is already attached has no
42 // effect, so we can do this.
43 NTPUserDataLogger::CreateForWebContents(content);
44 NTPUserDataLogger* logger = NTPUserDataLogger::FromWebContents(content);
45
46 // We record the URL of this NTP in order to identify navigations that
47 // originate from it. We use the NavigationController's URL since it might
48 // differ from the WebContents URL which is usually chrome://newtab/.
49 const content::NavigationEntry* entry =
50 content->GetController().GetVisibleEntry();
51 if (entry)
52 logger->ntp_url_ = entry->GetURL();
53
54 return logger;
55 }
56
EmitThumbnailErrorRate()57 void NTPUserDataLogger::EmitThumbnailErrorRate() {
58 DCHECK_LE(number_of_thumbnail_errors_, number_of_thumbnail_attempts_);
59 if (number_of_thumbnail_attempts_ != 0) {
60 UMA_HISTOGRAM_PERCENTAGE(
61 "NewTabPage.ThumbnailErrorRate",
62 GetPercentError(number_of_thumbnail_errors_,
63 number_of_thumbnail_attempts_));
64 }
65 DCHECK_LE(number_of_fallback_thumbnails_used_,
66 number_of_fallback_thumbnails_requested_);
67 if (number_of_fallback_thumbnails_requested_ != 0) {
68 UMA_HISTOGRAM_PERCENTAGE(
69 "NewTabPage.ThumbnailFallbackRate",
70 GetPercentError(number_of_fallback_thumbnails_used_,
71 number_of_fallback_thumbnails_requested_));
72 }
73 number_of_thumbnail_attempts_ = 0;
74 number_of_thumbnail_errors_ = 0;
75 number_of_fallback_thumbnails_requested_ = 0;
76 number_of_fallback_thumbnails_used_ = 0;
77 }
78
EmitNtpStatistics()79 void NTPUserDataLogger::EmitNtpStatistics() {
80 UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers", number_of_mouseovers_);
81 number_of_mouseovers_ = 0;
82 UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfExternalTiles",
83 number_of_external_tiles_);
84 number_of_external_tiles_ = 0;
85 UMA_HISTOGRAM_ENUMERATION(
86 "NewTabPage.SuggestionsType",
87 server_side_suggestions_ ? SERVER_SIDE : CLIENT_SIDE,
88 SUGGESTIONS_TYPE_COUNT);
89 server_side_suggestions_ = false;
90 }
91
LogEvent(NTPLoggingEventType event)92 void NTPUserDataLogger::LogEvent(NTPLoggingEventType event) {
93 switch (event) {
94 case NTP_MOUSEOVER:
95 number_of_mouseovers_++;
96 break;
97 case NTP_THUMBNAIL_ATTEMPT:
98 number_of_thumbnail_attempts_++;
99 break;
100 case NTP_THUMBNAIL_ERROR:
101 number_of_thumbnail_errors_++;
102 break;
103 case NTP_FALLBACK_THUMBNAIL_REQUESTED:
104 number_of_fallback_thumbnails_requested_++;
105 break;
106 case NTP_FALLBACK_THUMBNAIL_USED:
107 number_of_fallback_thumbnails_used_++;
108 break;
109 case NTP_SERVER_SIDE_SUGGESTION:
110 server_side_suggestions_ = true;
111 break;
112 case NTP_CLIENT_SIDE_SUGGESTION:
113 // We should never get a mix of server and client side suggestions,
114 // otherwise there could be a race condition depending on the order in
115 // which the iframes call this method.
116 DCHECK(!server_side_suggestions_);
117 break;
118 case NTP_EXTERNAL_TILE:
119 number_of_external_tiles_++;
120 break;
121 default:
122 NOTREACHED();
123 }
124 }
125
LogImpression(int position,const base::string16 & provider)126 void NTPUserDataLogger::LogImpression(int position,
127 const base::string16& provider) {
128 // Cannot rely on UMA histograms macro because the name of the histogram is
129 // generated dynamically.
130 base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
131 base::StringPrintf(kImpressionHistogramWithProvider,
132 UTF16ToUTF8(provider).c_str()),
133 1, MostVisitedIframeSource::kNumMostVisited,
134 MostVisitedIframeSource::kNumMostVisited + 1,
135 base::Histogram::kUmaTargetedHistogramFlag);
136 counter->Add(position);
137 }
138
139 // content::WebContentsObserver override
NavigationEntryCommitted(const content::LoadCommittedDetails & load_details)140 void NTPUserDataLogger::NavigationEntryCommitted(
141 const content::LoadCommittedDetails& load_details) {
142 if (!load_details.previous_url.is_valid())
143 return;
144
145 if (search::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) {
146 EmitNtpStatistics();
147 // Only log thumbnail error rates for Instant NTP pages, as we do not have
148 // this data for non-Instant NTPs.
149 if (ntp_url_ != GURL(chrome::kChromeUINewTabURL))
150 EmitThumbnailErrorRate();
151 }
152 }
153
NTPUserDataLogger(content::WebContents * contents)154 NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents)
155 : content::WebContentsObserver(contents),
156 number_of_mouseovers_(0),
157 number_of_thumbnail_attempts_(0),
158 number_of_thumbnail_errors_(0),
159 number_of_fallback_thumbnails_requested_(0),
160 number_of_fallback_thumbnails_used_(0),
161 number_of_external_tiles_(0),
162 server_side_suggestions_(false) {
163 }
164
GetPercentError(size_t errors,size_t events) const165 size_t NTPUserDataLogger::GetPercentError(size_t errors, size_t events) const {
166 return (100 * errors) / events;
167 }
168