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.
5 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
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/user_metrics.h"
17 #include "content/public/browser/web_contents.h"
19 // Macro to log UMA statistics related to the 8 tiles shown on the NTP.
20 #define UMA_HISTOGRAM_NTP_TILES(name, sample) \
21 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 0, 8, 9)
25 // Used to track if suggestions were issued by the client or the server.
26 enum SuggestionsType
{
29 SUGGESTIONS_TYPE_COUNT
= 2
32 // Number of Most Visited elements on the NTP for logging purposes.
33 const int kNumMostVisited
= 8;
35 // Name of the histogram keeping track of Most Visited impressions.
36 const char kMostVisitedImpressionHistogramName
[] =
37 "NewTabPage.SuggestionsImpression";
39 // Format string to generate the name for the histogram keeping track of
40 // suggestion impressions.
41 const char kMostVisitedImpressionHistogramWithProvider
[] =
42 "NewTabPage.SuggestionsImpression.%s";
44 // Name of the histogram keeping track of Most Visited navigations.
45 const char kMostVisitedNavigationHistogramName
[] =
46 "NewTabPage.MostVisited";
48 // Format string to generate the name for the histogram keeping track of
49 // suggestion navigations.
50 const char kMostVisitedNavigationHistogramWithProvider
[] =
51 "NewTabPage.MostVisited.%s";
55 DEFINE_WEB_CONTENTS_USER_DATA_KEY(NTPUserDataLogger
);
57 NTPUserDataLogger::~NTPUserDataLogger() {}
60 NTPUserDataLogger
* NTPUserDataLogger::GetOrCreateFromWebContents(
61 content::WebContents
* content
) {
62 // Calling CreateForWebContents when an instance is already attached has no
63 // effect, so we can do this.
64 NTPUserDataLogger::CreateForWebContents(content
);
65 NTPUserDataLogger
* logger
= NTPUserDataLogger::FromWebContents(content
);
67 // We record the URL of this NTP in order to identify navigations that
68 // originate from it. We use the NavigationController's URL since it might
69 // differ from the WebContents URL which is usually chrome://newtab/.
70 const content::NavigationEntry
* entry
=
71 content
->GetController().GetVisibleEntry();
73 logger
->ntp_url_
= entry
->GetURL();
79 std::string
NTPUserDataLogger::GetMostVisitedImpressionHistogramNameForProvider(
80 const std::string
& provider
) {
81 return base::StringPrintf(kMostVisitedImpressionHistogramWithProvider
,
86 std::string
NTPUserDataLogger::GetMostVisitedNavigationHistogramNameForProvider(
87 const std::string
& provider
) {
88 return base::StringPrintf(kMostVisitedNavigationHistogramWithProvider
,
92 void NTPUserDataLogger::EmitNtpStatistics() {
93 UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers", number_of_mouseovers_
);
94 number_of_mouseovers_
= 0;
96 // We only send statistics once per page.
97 // And we don't send if there are no tiles recorded.
98 if (has_emitted_
|| !number_of_tiles_
)
101 UMA_HISTOGRAM_ENUMERATION(
102 "NewTabPage.SuggestionsType",
103 has_server_side_suggestions_
? SERVER_SIDE
: CLIENT_SIDE
,
104 SUGGESTIONS_TYPE_COUNT
);
105 has_server_side_suggestions_
= false;
106 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfTiles", number_of_tiles_
);
107 number_of_tiles_
= 0;
108 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailTiles",
109 number_of_thumbnail_tiles_
);
110 number_of_thumbnail_tiles_
= 0;
111 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTiles",
112 number_of_gray_tiles_
);
113 number_of_gray_tiles_
= 0;
114 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTiles",
115 number_of_external_tiles_
);
116 number_of_external_tiles_
= 0;
117 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailErrors",
118 number_of_thumbnail_errors_
);
119 number_of_thumbnail_errors_
= 0;
120 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTileFallbacks",
121 number_of_gray_tile_fallbacks_
);
122 number_of_gray_tile_fallbacks_
= 0;
123 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks",
124 number_of_external_tile_fallbacks_
);
125 number_of_external_tile_fallbacks_
= 0;
126 UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.LoadTime",
128 base::TimeDelta::FromMilliseconds(1),
129 base::TimeDelta::FromSeconds(60), 100);
130 load_time_
= base::TimeDelta::FromMilliseconds(0);
134 void NTPUserDataLogger::LogEvent(NTPLoggingEventType event
,
135 base::TimeDelta time
) {
137 case NTP_SERVER_SIDE_SUGGESTION
:
138 has_server_side_suggestions_
= true;
140 case NTP_CLIENT_SIDE_SUGGESTION
:
141 // We should never get a mix of server and client side suggestions,
142 // otherwise there could be a race condition depending on the order in
143 // which the iframes call this method.
144 DCHECK(!has_server_side_suggestions_
);
149 case NTP_THUMBNAIL_TILE
:
150 number_of_thumbnail_tiles_
++;
153 number_of_gray_tiles_
++;
155 case NTP_EXTERNAL_TILE
:
156 number_of_external_tiles_
++;
158 case NTP_THUMBNAIL_ERROR
:
159 number_of_thumbnail_errors_
++;
161 case NTP_GRAY_TILE_FALLBACK
:
162 number_of_gray_tile_fallbacks_
++;
164 case NTP_EXTERNAL_TILE_FALLBACK
:
165 number_of_external_tile_fallbacks_
++;
168 number_of_mouseovers_
++;
170 case NTP_TILE_LOADED
:
171 // The time at which the last tile has loaded (title, thumbnail or single)
172 // is a good proxy for the total load time of the NTP, therefore we keep
173 // the max as the load time.
174 load_time_
= std::max(load_time_
, time
);
181 void NTPUserDataLogger::LogMostVisitedImpression(
182 int position
, const base::string16
& provider
) {
183 // Log the Most Visited navigation for navigations that have providers and
185 UMA_HISTOGRAM_ENUMERATION(kMostVisitedImpressionHistogramName
, position
,
188 // If a provider is specified, log the metric specific to it.
189 if (!provider
.empty()) {
190 // Cannot rely on UMA histograms macro because the name of the histogram is
191 // generated dynamically.
192 base::HistogramBase
* counter
= base::LinearHistogram::FactoryGet(
193 GetMostVisitedImpressionHistogramNameForProvider(
194 base::UTF16ToUTF8(provider
)),
198 base::Histogram::kUmaTargetedHistogramFlag
);
199 counter
->Add(position
);
203 void NTPUserDataLogger::LogMostVisitedNavigation(
204 int position
, const base::string16
& provider
) {
205 // Log the Most Visited navigation for navigations that have providers and
207 UMA_HISTOGRAM_ENUMERATION(kMostVisitedNavigationHistogramName
, position
,
210 // If a provider is specified, log the metric specific to it.
211 if (!provider
.empty()) {
212 // Cannot rely on UMA histograms macro because the name of the histogram is
213 // generated dynamically.
214 base::HistogramBase
* counter
= base::LinearHistogram::FactoryGet(
215 GetMostVisitedNavigationHistogramNameForProvider(
216 base::UTF16ToUTF8(provider
)),
220 base::Histogram::kUmaTargetedHistogramFlag
);
221 counter
->Add(position
);
224 // Records the action. This will be available as a time-stamped stream
225 // server-side and can be used to compute time-to-long-dwell.
226 content::RecordAction(base::UserMetricsAction("MostVisited_Clicked"));
229 // content::WebContentsObserver override
230 void NTPUserDataLogger::NavigationEntryCommitted(
231 const content::LoadCommittedDetails
& load_details
) {
232 if (!load_details
.previous_url
.is_valid())
235 if (search::MatchesOriginAndPath(ntp_url_
, load_details
.previous_url
)) {
240 NTPUserDataLogger::NTPUserDataLogger(content::WebContents
* contents
)
241 : content::WebContentsObserver(contents
),
242 has_server_side_suggestions_(false),
244 number_of_thumbnail_tiles_(0),
245 number_of_gray_tiles_(0),
246 number_of_external_tiles_(0),
247 number_of_thumbnail_errors_(0),
248 number_of_gray_tile_fallbacks_(0),
249 number_of_external_tile_fallbacks_(0),
250 number_of_mouseovers_(0),
251 has_emitted_(false) {