Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_usage_stats.cc
blobb274e07cac4d8dc35e22fd53684c3edb0d8acd05
1 // Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/sparse_histogram.h"
12 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
13 #include "net/base/net_errors.h"
14 #include "net/proxy/proxy_retry_info.h"
15 #include "net/proxy/proxy_server.h"
16 #include "net/proxy/proxy_service.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_context.h"
20 using base::MessageLoopProxy;
21 using net::HostPortPair;
22 using net::ProxyServer;
23 using net::ProxyService;
24 using net::NetworkChangeNotifier;
25 using net::URLRequest;
27 namespace data_reduction_proxy {
29 namespace {
31 // Records a net error code that resulted in bypassing the data reduction
32 // proxy (|is_primary| is true) or the data reduction proxy fallback.
33 void RecordDataReductionProxyBypassOnNetworkError(
34 bool is_primary,
35 const ProxyServer& proxy_server,
36 int net_error) {
37 if (is_primary) {
38 UMA_HISTOGRAM_SPARSE_SLOWLY(
39 "DataReductionProxy.BypassOnNetworkErrorPrimary",
40 std::abs(net_error));
41 return;
43 UMA_HISTOGRAM_SPARSE_SLOWLY(
44 "DataReductionProxy.BypassOnNetworkErrorFallback",
45 std::abs(net_error));
48 } // namespace
50 // static
51 void DataReductionProxyUsageStats::RecordDataReductionProxyBypassInfo(
52 bool is_primary,
53 bool bypass_all,
54 const net::ProxyServer& proxy_server,
55 DataReductionProxyBypassType bypass_type) {
56 if (bypass_all) {
57 if (is_primary) {
58 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypePrimary",
59 bypass_type, BYPASS_EVENT_TYPE_MAX);
60 } else {
61 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypeFallback",
62 bypass_type, BYPASS_EVENT_TYPE_MAX);
64 } else {
65 if (is_primary) {
66 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypePrimary",
67 bypass_type, BYPASS_EVENT_TYPE_MAX);
68 } else {
69 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypeFallback",
70 bypass_type, BYPASS_EVENT_TYPE_MAX);
75 DataReductionProxyUsageStats::DataReductionProxyUsageStats(
76 DataReductionProxyParams* params,
77 MessageLoopProxy* ui_thread_proxy)
78 : data_reduction_proxy_params_(params),
79 last_bypass_type_(BYPASS_EVENT_TYPE_MAX),
80 triggering_request_(true),
81 ui_thread_proxy_(ui_thread_proxy),
82 eligible_num_requests_through_proxy_(0),
83 actual_num_requests_through_proxy_(0),
84 unavailable_(false) {
85 NetworkChangeNotifier::AddNetworkChangeObserver(this);
88 DataReductionProxyUsageStats::~DataReductionProxyUsageStats() {
89 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
92 void DataReductionProxyUsageStats::OnUrlRequestCompleted(
93 const net::URLRequest* request, bool started) {
94 DCHECK(thread_checker_.CalledOnValidThread());
96 if (request->status().status() == net::URLRequestStatus::SUCCESS) {
97 if (data_reduction_proxy_params_->IsDataReductionProxyEligible(request)) {
98 bool was_received_via_proxy =
99 data_reduction_proxy_params_->WasDataReductionProxyUsed(
100 request, NULL);
101 IncrementRequestCounts(was_received_via_proxy);
106 void DataReductionProxyUsageStats::OnNetworkChanged(
107 NetworkChangeNotifier::ConnectionType type) {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 ClearRequestCounts();
112 void DataReductionProxyUsageStats::IncrementRequestCounts(
113 bool was_received_via_proxy) {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 if (was_received_via_proxy) {
116 actual_num_requests_through_proxy_++;
118 eligible_num_requests_through_proxy_++;
120 // To account for the case when the proxy works for a little while and then
121 // gets blocked, we reset the counts occasionally.
122 if (eligible_num_requests_through_proxy_ > 50
123 && actual_num_requests_through_proxy_ > 0) {
124 ClearRequestCounts();
125 } else {
126 MaybeNotifyUnavailability();
130 void DataReductionProxyUsageStats::ClearRequestCounts() {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 eligible_num_requests_through_proxy_ = 0;
133 actual_num_requests_through_proxy_ = 0;
134 MaybeNotifyUnavailability();
137 void DataReductionProxyUsageStats::MaybeNotifyUnavailability() {
138 bool prev_unavailable = unavailable_;
139 unavailable_ = (eligible_num_requests_through_proxy_ > 0 &&
140 actual_num_requests_through_proxy_ == 0);
141 if (prev_unavailable != unavailable_) {
142 ui_thread_proxy_->PostTask(FROM_HERE, base::Bind(
143 &DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread,
144 base::Unretained(this),
145 unavailable_));
149 void DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread(
150 bool unavailable) {
151 DCHECK(ui_thread_proxy_->BelongsToCurrentThread());
152 if (!unavailable_callback_.is_null())
153 unavailable_callback_.Run(unavailable);
156 void DataReductionProxyUsageStats::SetBypassType(
157 DataReductionProxyBypassType type) {
158 last_bypass_type_ = type;
159 triggering_request_ = true;
162 void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
163 net::URLRequest& request,
164 const BooleanPrefMember& data_reduction_proxy_enabled) {
165 int64 content_length = request.received_response_content_length();
166 if (data_reduction_proxy_params_->WasDataReductionProxyUsed(&request, NULL)) {
167 RecordBypassedBytes(last_bypass_type_,
168 DataReductionProxyUsageStats::NOT_BYPASSED,
169 content_length);
170 return;
173 if (data_reduction_proxy_enabled.GetValue() &&
174 request.url().SchemeIs(url::kHttpsScheme)) {
175 RecordBypassedBytes(last_bypass_type_,
176 DataReductionProxyUsageStats::SSL,
177 content_length);
178 return;
181 if (data_reduction_proxy_enabled.GetValue() &&
182 !data_reduction_proxy_params_->IsDataReductionProxyEligible(&request)) {
183 RecordBypassedBytes(last_bypass_type_,
184 DataReductionProxyUsageStats::LOCAL_BYPASS_RULES,
185 content_length);
186 return;
189 if (triggering_request_) {
190 RecordBypassedBytes(last_bypass_type_,
191 DataReductionProxyUsageStats::TRIGGERING_REQUEST,
192 content_length);
193 triggering_request_ = false;
195 // We only record when audio or video triggers a bypass. We don't care
196 // about audio and video bypassed as collateral damage.
197 std::string mime_type;
198 request.GetMimeType(&mime_type);
199 // MIME types are named by <media-type>/<subtype>. We check to see if the
200 // media type is audio or video.
201 if (mime_type.compare(0, 6, "audio/") == 0 ||
202 mime_type.compare(0, 6, "video/") == 0) {
203 RecordBypassedBytes(last_bypass_type_,
204 DataReductionProxyUsageStats::AUDIO_VIDEO,
205 content_length);
209 if (last_bypass_type_ != BYPASS_EVENT_TYPE_MAX) {
210 RecordBypassedBytes(last_bypass_type_,
211 DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX,
212 content_length);
213 return;
216 if (data_reduction_proxy_params_->
217 AreDataReductionProxiesBypassed(request, NULL)) {
218 RecordBypassedBytes(last_bypass_type_,
219 DataReductionProxyUsageStats::NETWORK_ERROR,
220 content_length);
224 void DataReductionProxyUsageStats::RecordBypassEventHistograms(
225 const net::ProxyServer& bypassed_proxy,
226 int net_error) const {
227 DataReductionProxyTypeInfo data_reduction_proxy_info;
228 if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
229 data_reduction_proxy_params_->IsDataReductionProxy(
230 bypassed_proxy.host_port_pair(), &data_reduction_proxy_info)) {
231 if (data_reduction_proxy_info.is_ssl)
232 return;
233 if (!data_reduction_proxy_info.is_fallback) {
234 RecordDataReductionProxyBypassInfo(
235 true, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
236 RecordDataReductionProxyBypassOnNetworkError(
237 true, bypassed_proxy, net_error);
238 } else {
239 RecordDataReductionProxyBypassInfo(
240 false, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
241 RecordDataReductionProxyBypassOnNetworkError(
242 false, bypassed_proxy, net_error);
247 void DataReductionProxyUsageStats::RecordBypassedBytes(
248 DataReductionProxyBypassType bypass_type,
249 DataReductionProxyUsageStats::BypassedBytesType bypassed_bytes_type,
250 int64 content_length) {
251 // Individual histograms are needed to count the bypassed bytes for each
252 // bypass type so that we can see the size of requests. This helps us
253 // remove outliers that would skew the sum of bypassed bytes for each type.
254 switch (bypassed_bytes_type) {
255 case DataReductionProxyUsageStats::NOT_BYPASSED:
256 UMA_HISTOGRAM_COUNTS(
257 "DataReductionProxy.BypassedBytes.NotBypassed", content_length);
258 break;
259 case DataReductionProxyUsageStats::SSL:
260 UMA_HISTOGRAM_COUNTS(
261 "DataReductionProxy.BypassedBytes.SSL", content_length);
262 break;
263 case DataReductionProxyUsageStats::LOCAL_BYPASS_RULES:
264 UMA_HISTOGRAM_COUNTS(
265 "DataReductionProxy.BypassedBytes.LocalBypassRules",
266 content_length);
267 break;
268 case DataReductionProxyUsageStats::AUDIO_VIDEO:
269 if (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT) {
270 UMA_HISTOGRAM_COUNTS(
271 "DataReductionProxy.BypassedBytes.ShortAudioVideo",
272 content_length);
274 break;
275 case DataReductionProxyUsageStats::TRIGGERING_REQUEST:
276 switch (bypass_type) {
277 case BYPASS_EVENT_TYPE_SHORT:
278 UMA_HISTOGRAM_COUNTS(
279 "DataReductionProxy.BypassedBytes.ShortTriggeringRequest",
280 content_length);
281 break;
282 case BYPASS_EVENT_TYPE_MEDIUM:
283 UMA_HISTOGRAM_COUNTS(
284 "DataReductionProxy.BypassedBytes.MediumTriggeringRequest",
285 content_length);
286 break;
287 case BYPASS_EVENT_TYPE_LONG:
288 UMA_HISTOGRAM_COUNTS(
289 "DataReductionProxy.BypassedBytes.LongTriggeringRequest",
290 content_length);
291 break;
292 default:
293 break;
295 break;
296 case DataReductionProxyUsageStats::NETWORK_ERROR:
297 UMA_HISTOGRAM_COUNTS(
298 "DataReductionProxy.BypassedBytes.NetworkErrorOther",
299 content_length);
300 break;
301 case DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX:
302 switch (bypass_type) {
303 case BYPASS_EVENT_TYPE_CURRENT:
304 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Current",
305 content_length);
306 break;
307 case BYPASS_EVENT_TYPE_SHORT:
308 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.ShortAll",
309 content_length);
310 break;
311 case BYPASS_EVENT_TYPE_MEDIUM:
312 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.MediumAll",
313 content_length);
314 break;
315 case BYPASS_EVENT_TYPE_LONG:
316 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.LongAll",
317 content_length);
318 break;
319 case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX:
320 UMA_HISTOGRAM_COUNTS(
321 "DataReductionProxy.BypassedBytes.MissingViaHeader4xx",
322 content_length);
323 break;
324 case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER:
325 UMA_HISTOGRAM_COUNTS(
326 "DataReductionProxy.BypassedBytes.MissingViaHeaderOther",
327 content_length);
328 break;
329 case BYPASS_EVENT_TYPE_MALFORMED_407:
330 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Malformed407",
331 content_length);
332 break;
333 case BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR:
334 UMA_HISTOGRAM_COUNTS(
335 "DataReductionProxy.BypassedBytes."
336 "Status500HttpInternalServerError",
337 content_length);
338 break;
339 case BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY:
340 UMA_HISTOGRAM_COUNTS(
341 "DataReductionProxy.BypassedBytes.Status502HttpBadGateway",
342 content_length);
343 break;
344 case BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE:
345 UMA_HISTOGRAM_COUNTS(
346 "DataReductionProxy.BypassedBytes."
347 "Status503HttpServiceUnavailable",
348 content_length);
349 break;
350 default:
351 break;
353 break;
357 } // namespace data_reduction_proxy