OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h" | 5 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> |
8 | 9 |
9 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
10 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "chrome/browser/after_startup_task_utils.h" | 12 #include "chrome/browser/after_startup_task_utils.h" |
13 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
14 #include "chrome/browser/search/most_visited_iframe_source.h" | |
15 #include "chrome/browser/search/search.h" | 14 #include "chrome/browser/search/search.h" |
16 #include "chrome/browser/sync/profile_sync_service_factory.h" | 15 #include "chrome/browser/sync/profile_sync_service_factory.h" |
17 #include "chrome/common/search/search_urls.h" | 16 #include "chrome/common/search/search_urls.h" |
18 #include "chrome/common/url_constants.h" | 17 #include "chrome/common/url_constants.h" |
19 #include "components/browser_sync/browser/profile_sync_service.h" | 18 #include "components/browser_sync/browser/profile_sync_service.h" |
20 #include "components/sync_sessions/sessions_sync_manager.h" | 19 #include "components/sync_sessions/sessions_sync_manager.h" |
21 #include "components/sync_sessions/sync_sessions_metrics.h" | 20 #include "components/sync_sessions/sync_sessions_metrics.h" |
22 #include "content/public/browser/navigation_details.h" | 21 #include "content/public/browser/navigation_details.h" |
23 #include "content/public/browser/navigation_entry.h" | 22 #include "content/public/browser/navigation_entry.h" |
24 #include "content/public/browser/user_metrics.h" | 23 #include "content/public/browser/user_metrics.h" |
25 #include "content/public/browser/web_contents.h" | 24 #include "content/public/browser/web_contents.h" |
26 | 25 |
27 // Macro to log UMA statistics related to the 8 tiles shown on the NTP. | |
28 #define UMA_HISTOGRAM_NTP_TILES(name, sample) \ | |
29 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 0, 8, 9) | |
30 | |
31 namespace { | 26 namespace { |
32 | 27 |
33 // Used to track if suggestions were issued by the client or the server. | |
34 enum SuggestionsType { | |
35 CLIENT_SIDE = 0, | |
36 SERVER_SIDE = 1, | |
37 SUGGESTIONS_TYPE_COUNT = 2 | |
38 }; | |
39 | |
40 // Number of Most Visited elements on the NTP for logging purposes. | 28 // Number of Most Visited elements on the NTP for logging purposes. |
41 const int kNumMostVisited = 8; | 29 const int kNumMostVisited = 8; |
42 | 30 |
43 // Name of the histogram keeping track of suggestion impressions. | 31 // Name of the histogram keeping track of suggestion impressions. |
44 const char kMostVisitedImpressionHistogramName[] = | 32 const char kMostVisitedImpressionHistogramName[] = |
45 "NewTabPage.SuggestionsImpression"; | 33 "NewTabPage.SuggestionsImpression"; |
46 | 34 |
47 // Format string to generate the name for the histogram keeping track of | 35 // Format string to generate the name for the histogram keeping track of |
48 // suggestion impressions. | 36 // suggestion impressions. |
49 const char kMostVisitedImpressionHistogramWithProvider[] = | 37 const char kMostVisitedImpressionHistogramWithProvider[] = |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 has_server_side_suggestions_ = true; | 109 has_server_side_suggestions_ = true; |
122 break; | 110 break; |
123 case NTP_CLIENT_SIDE_SUGGESTION: | 111 case NTP_CLIENT_SIDE_SUGGESTION: |
124 if (has_server_side_suggestions_) | 112 if (has_server_side_suggestions_) |
125 EmitNtpStatistics(EmitReason::INTERNAL_FLUSH); | 113 EmitNtpStatistics(EmitReason::INTERNAL_FLUSH); |
126 has_client_side_suggestions_ = true; | 114 has_client_side_suggestions_ = true; |
127 break; | 115 break; |
128 case NTP_TILE: | 116 case NTP_TILE: |
129 number_of_tiles_++; | 117 number_of_tiles_++; |
130 break; | 118 break; |
131 case NTP_THUMBNAIL_TILE: | |
132 number_of_thumbnail_tiles_++; | |
133 break; | |
134 case NTP_GRAY_TILE: | |
135 number_of_gray_tiles_++; | |
136 break; | |
137 case NTP_EXTERNAL_TILE: | |
138 number_of_external_tiles_++; | |
139 break; | |
140 case NTP_THUMBNAIL_ERROR: | |
141 number_of_thumbnail_errors_++; | |
142 break; | |
143 case NTP_GRAY_TILE_FALLBACK: | |
144 number_of_gray_tile_fallbacks_++; | |
145 break; | |
146 case NTP_EXTERNAL_TILE_FALLBACK: | |
147 number_of_external_tile_fallbacks_++; | |
148 break; | |
149 case NTP_TILE_LOADED: | 119 case NTP_TILE_LOADED: |
150 // The time at which the last tile has loaded (title, thumbnail or single) | 120 // The time at which the last tile has loaded (title, thumbnail or single) |
151 // is a good proxy for the total load time of the NTP, therefore we keep | 121 // is a good proxy for the total load time of the NTP, therefore we keep |
152 // the max as the load time. | 122 // the max as the load time. |
153 load_time_ = std::max(load_time_, time); | 123 load_time_ = std::max(load_time_, time); |
154 break; | 124 break; |
155 default: | 125 default: |
156 NOTREACHED(); | 126 NOTREACHED(); |
157 } | 127 } |
158 } | 128 } |
(...skipping 29 matching lines...) Expand all Loading... |
188 kNumMostVisited, | 158 kNumMostVisited, |
189 kNumMostVisited + 1, | 159 kNumMostVisited + 1, |
190 base::Histogram::kUmaTargetedHistogramFlag); | 160 base::Histogram::kUmaTargetedHistogramFlag); |
191 counter->Add(position); | 161 counter->Add(position); |
192 | 162 |
193 // Records the action. This will be available as a time-stamped stream | 163 // Records the action. This will be available as a time-stamped stream |
194 // server-side and can be used to compute time-to-long-dwell. | 164 // server-side and can be used to compute time-to-long-dwell. |
195 content::RecordAction(base::UserMetricsAction("MostVisited_Clicked")); | 165 content::RecordAction(base::UserMetricsAction("MostVisited_Clicked")); |
196 } | 166 } |
197 | 167 |
198 // content::WebContentsObserver override | |
199 void NTPUserDataLogger::NavigationEntryCommitted( | |
200 const content::LoadCommittedDetails& load_details) { | |
201 if (!load_details.previous_url.is_valid()) | |
202 return; | |
203 | |
204 if (search::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) { | |
205 EmitNtpStatistics(EmitReason::NAVIGATED_AWAY); | |
206 } | |
207 } | |
208 | |
209 void NTPUserDataLogger::TabDeactivated() { | 168 void NTPUserDataLogger::TabDeactivated() { |
210 EmitNtpStatistics(EmitReason::CLOSED); | 169 EmitNtpStatistics(EmitReason::CLOSED); |
211 } | 170 } |
212 | 171 |
213 void NTPUserDataLogger::MostVisitedItemsChanged() { | 172 void NTPUserDataLogger::MostVisitedItemsChanged() { |
214 EmitNtpStatistics(EmitReason::MV_CHANGED); | 173 EmitNtpStatistics(EmitReason::MV_CHANGED); |
215 } | 174 } |
216 | 175 |
217 NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents) | 176 NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents) |
218 : content::WebContentsObserver(contents), | 177 : content::WebContentsObserver(contents), |
219 has_server_side_suggestions_(false), | 178 has_server_side_suggestions_(false), |
220 has_client_side_suggestions_(false), | 179 has_client_side_suggestions_(false), |
221 number_of_tiles_(0), | 180 number_of_tiles_(0), |
222 number_of_thumbnail_tiles_(0), | |
223 number_of_gray_tiles_(0), | |
224 number_of_external_tiles_(0), | |
225 number_of_thumbnail_errors_(0), | |
226 number_of_gray_tile_fallbacks_(0), | |
227 number_of_external_tile_fallbacks_(0), | |
228 has_emitted_(false), | 181 has_emitted_(false), |
229 during_startup_(false) { | 182 during_startup_(false) { |
230 during_startup_ = !AfterStartupTaskUtils::IsBrowserStartupComplete(); | 183 during_startup_ = !AfterStartupTaskUtils::IsBrowserStartupComplete(); |
231 | 184 |
232 // We record metrics about session data here because when this class typically | 185 // We record metrics about session data here because when this class typically |
233 // emits metrics it is too late. This session data would theoretically have | 186 // emits metrics it is too late. This session data would theoretically have |
234 // been used to populate the page, and we want to learn about its state when | 187 // been used to populate the page, and we want to learn about its state when |
235 // the NTP is being generated. | 188 // the NTP is being generated. |
236 if (contents) { | 189 if (contents) { |
237 ProfileSyncService* sync = ProfileSyncServiceFactory::GetForProfile( | 190 ProfileSyncService* sync = ProfileSyncServiceFactory::GetForProfile( |
238 Profile::FromBrowserContext(contents->GetBrowserContext())); | 191 Profile::FromBrowserContext(contents->GetBrowserContext())); |
239 if (sync) { | 192 if (sync) { |
240 browser_sync::SessionsSyncManager* sessions = | 193 browser_sync::SessionsSyncManager* sessions = |
241 static_cast<browser_sync::SessionsSyncManager*>( | 194 static_cast<browser_sync::SessionsSyncManager*>( |
242 sync->GetSessionsSyncableService()); | 195 sync->GetSessionsSyncableService()); |
243 if (sessions) { | 196 if (sessions) { |
244 sync_sessions::SyncSessionsMetrics::RecordYoungestForeignTabAgeOnNTP( | 197 sync_sessions::SyncSessionsMetrics::RecordYoungestForeignTabAgeOnNTP( |
245 sessions); | 198 sessions); |
246 } | 199 } |
247 } | 200 } |
248 } | 201 } |
249 } | 202 } |
250 | 203 |
| 204 // content::WebContentsObserver override |
| 205 void NTPUserDataLogger::NavigationEntryCommitted( |
| 206 const content::LoadCommittedDetails& load_details) { |
| 207 if (!load_details.previous_url.is_valid()) |
| 208 return; |
| 209 |
| 210 if (search::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) |
| 211 EmitNtpStatistics(EmitReason::NAVIGATED_AWAY); |
| 212 } |
| 213 |
251 void NTPUserDataLogger::EmitNtpStatistics(EmitReason reason) { | 214 void NTPUserDataLogger::EmitNtpStatistics(EmitReason reason) { |
252 // We only send statistics once per page. | 215 // We only send statistics once per page. |
253 // And we don't send if there are no tiles recorded. | 216 // And we don't send if there are no tiles recorded. |
254 if (has_emitted_ || !number_of_tiles_) | 217 if (has_emitted_ || !number_of_tiles_) |
255 return; | 218 return; |
256 | 219 |
257 // LoadTime only gets update once per page, so we don't have it on reloads. | 220 // LoadTime only gets update once per page, so we don't have it on reloads. |
258 if (load_time_ > base::TimeDelta::FromMilliseconds(0)) { | 221 if (load_time_ > base::TimeDelta::FromMilliseconds(0)) { |
259 logLoadTimeHistogram("NewTabPage.LoadTime", load_time_); | 222 logLoadTimeHistogram("NewTabPage.LoadTime", load_time_); |
260 | 223 |
261 // Split between ML and MV. | 224 // Split between ML and MV. |
262 std::string type = has_server_side_suggestions_ ? | 225 std::string type = has_server_side_suggestions_ ? |
263 "MostLikely" : "MostVisited"; | 226 "MostLikely" : "MostVisited"; |
264 logLoadTimeHistogram("NewTabPage.LoadTime." + type, load_time_); | 227 logLoadTimeHistogram("NewTabPage.LoadTime." + type, load_time_); |
265 // Split between Web and Local. | 228 // Split between Web and Local. |
266 std::string source = ntp_url_.SchemeIsHTTPOrHTTPS() ? "Web" : "LocalNTP"; | 229 std::string source = ntp_url_.SchemeIsHTTPOrHTTPS() ? "Web" : "LocalNTP"; |
267 logLoadTimeHistogram("NewTabPage.LoadTime." + source, load_time_); | 230 logLoadTimeHistogram("NewTabPage.LoadTime." + source, load_time_); |
268 | 231 |
269 // Split between Startup and non-startup. | 232 // Split between Startup and non-startup. |
270 std::string status = during_startup_ ? "Startup" : "NewTab"; | 233 std::string status = during_startup_ ? "Startup" : "NewTab"; |
271 logLoadTimeHistogram("NewTabPage.LoadTime." + status, load_time_); | 234 logLoadTimeHistogram("NewTabPage.LoadTime." + status, load_time_); |
272 | 235 |
273 load_time_ = base::TimeDelta::FromMilliseconds(0); | 236 load_time_ = base::TimeDelta::FromMilliseconds(0); |
274 } | 237 } |
275 UMA_HISTOGRAM_ENUMERATION( | |
276 "NewTabPage.SuggestionsType", | |
277 has_server_side_suggestions_ ? SERVER_SIDE : CLIENT_SIDE, | |
278 SUGGESTIONS_TYPE_COUNT); | |
279 has_server_side_suggestions_ = false; | 238 has_server_side_suggestions_ = false; |
280 has_client_side_suggestions_ = false; | 239 has_client_side_suggestions_ = false; |
281 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfTiles", number_of_tiles_); | 240 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 241 "NewTabPage.NumberOfTiles", number_of_tiles_, 0, kNumMostVisited, |
| 242 kNumMostVisited + 1); |
282 number_of_tiles_ = 0; | 243 number_of_tiles_ = 0; |
283 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailTiles", | |
284 number_of_thumbnail_tiles_); | |
285 number_of_thumbnail_tiles_ = 0; | |
286 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTiles", | |
287 number_of_gray_tiles_); | |
288 number_of_gray_tiles_ = 0; | |
289 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTiles", | |
290 number_of_external_tiles_); | |
291 number_of_external_tiles_ = 0; | |
292 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailErrors", | |
293 number_of_thumbnail_errors_); | |
294 number_of_thumbnail_errors_ = 0; | |
295 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTileFallbacks", | |
296 number_of_gray_tile_fallbacks_); | |
297 number_of_gray_tile_fallbacks_ = 0; | |
298 UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks", | |
299 number_of_external_tile_fallbacks_); | |
300 number_of_external_tile_fallbacks_ = 0; | |
301 has_emitted_ = true; | 244 has_emitted_ = true; |
302 during_startup_ = false; | 245 during_startup_ = false; |
303 } | 246 } |
OLD | NEW |