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 has_client_side_suggestions_
= false;
107 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfTiles", number_of_tiles_
);
108 number_of_tiles_
= 0;
109 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailTiles",
110 number_of_thumbnail_tiles_
);
111 number_of_thumbnail_tiles_
= 0;
112 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTiles",
113 number_of_gray_tiles_
);
114 number_of_gray_tiles_
= 0;
115 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTiles",
116 number_of_external_tiles_
);
117 number_of_external_tiles_
= 0;
118 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailErrors",
119 number_of_thumbnail_errors_
);
120 number_of_thumbnail_errors_
= 0;
121 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTileFallbacks",
122 number_of_gray_tile_fallbacks_
);
123 number_of_gray_tile_fallbacks_
= 0;
124 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks",
125 number_of_external_tile_fallbacks_
);
126 number_of_external_tile_fallbacks_
= 0;
127 UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.LoadTime",
129 base::TimeDelta::FromMilliseconds(1),
130 base::TimeDelta::FromSeconds(60), 100);
131 load_time_
= base::TimeDelta::FromMilliseconds(0);
135 void NTPUserDataLogger::LogEvent(NTPLoggingEventType event
,
136 base::TimeDelta time
) {
138 // It is possible that our page gets update with a different set of
139 // suggestions if the NTP is left open enough time.
140 // In either case, we want to flush our stats before recounting again.
141 case NTP_SERVER_SIDE_SUGGESTION
:
142 if (has_client_side_suggestions_
)
144 has_server_side_suggestions_
= true;
146 case NTP_CLIENT_SIDE_SUGGESTION
:
147 if (has_server_side_suggestions_
)
149 has_client_side_suggestions_
= true;
154 case NTP_THUMBNAIL_TILE
:
155 number_of_thumbnail_tiles_
++;
158 number_of_gray_tiles_
++;
160 case NTP_EXTERNAL_TILE
:
161 number_of_external_tiles_
++;
163 case NTP_THUMBNAIL_ERROR
:
164 number_of_thumbnail_errors_
++;
166 case NTP_GRAY_TILE_FALLBACK
:
167 number_of_gray_tile_fallbacks_
++;
169 case NTP_EXTERNAL_TILE_FALLBACK
:
170 number_of_external_tile_fallbacks_
++;
173 number_of_mouseovers_
++;
175 case NTP_TILE_LOADED
:
176 // The time at which the last tile has loaded (title, thumbnail or single)
177 // is a good proxy for the total load time of the NTP, therefore we keep
178 // the max as the load time.
179 load_time_
= std::max(load_time_
, time
);
186 void NTPUserDataLogger::LogMostVisitedImpression(
187 int position
, const base::string16
& provider
) {
188 // Log the Most Visited navigation for navigations that have providers and
190 UMA_HISTOGRAM_ENUMERATION(kMostVisitedImpressionHistogramName
, position
,
193 // If a provider is specified, log the metric specific to it.
194 if (!provider
.empty()) {
195 // Cannot rely on UMA histograms macro because the name of the histogram is
196 // generated dynamically.
197 base::HistogramBase
* counter
= base::LinearHistogram::FactoryGet(
198 GetMostVisitedImpressionHistogramNameForProvider(
199 base::UTF16ToUTF8(provider
)),
203 base::Histogram::kUmaTargetedHistogramFlag
);
204 counter
->Add(position
);
208 void NTPUserDataLogger::LogMostVisitedNavigation(
209 int position
, const base::string16
& provider
) {
210 // Log the Most Visited navigation for navigations that have providers and
212 UMA_HISTOGRAM_ENUMERATION(kMostVisitedNavigationHistogramName
, position
,
215 // If a provider is specified, log the metric specific to it.
216 if (!provider
.empty()) {
217 // Cannot rely on UMA histograms macro because the name of the histogram is
218 // generated dynamically.
219 base::HistogramBase
* counter
= base::LinearHistogram::FactoryGet(
220 GetMostVisitedNavigationHistogramNameForProvider(
221 base::UTF16ToUTF8(provider
)),
225 base::Histogram::kUmaTargetedHistogramFlag
);
226 counter
->Add(position
);
229 // Records the action. This will be available as a time-stamped stream
230 // server-side and can be used to compute time-to-long-dwell.
231 content::RecordAction(base::UserMetricsAction("MostVisited_Clicked"));
234 // content::WebContentsObserver override
235 void NTPUserDataLogger::NavigationEntryCommitted(
236 const content::LoadCommittedDetails
& load_details
) {
237 if (!load_details
.previous_url
.is_valid())
240 if (search::MatchesOriginAndPath(ntp_url_
, load_details
.previous_url
)) {
245 NTPUserDataLogger::NTPUserDataLogger(content::WebContents
* contents
)
246 : content::WebContentsObserver(contents
),
247 has_server_side_suggestions_(false),
248 has_client_side_suggestions_(false),
250 number_of_thumbnail_tiles_(0),
251 number_of_gray_tiles_(0),
252 number_of_external_tiles_(0),
253 number_of_thumbnail_errors_(0),
254 number_of_gray_tile_fallbacks_(0),
255 number_of_external_tile_fallbacks_(0),
256 number_of_mouseovers_(0),
257 has_emitted_(false) {