Add diagnostics_writer.cc to the list of files allowed to printf.
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_metrics.cc
blob795dbea03dc53e340e32bceadc20f70278643806
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_metrics.h"
7 #include "base/metrics/histogram.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
13 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
14 #include "components/data_reduction_proxy/common/data_reduction_proxy_pref_names.h"
15 #include "net/base/host_port_pair.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/proxy/proxy_retry_info.h"
18 #include "net/proxy/proxy_service.h"
19 #include "net/url_request/url_request_context.h"
21 namespace data_reduction_proxy {
23 namespace {
25 #if defined(SPDY_PROXY_AUTH_ORIGIN)
26 // A bypass delay more than this is treated as a long delay.
27 const int kLongBypassDelayInSeconds = 30 * 60;
28 #endif
30 // Increments an int64, stored as a string, in a ListPref at the specified
31 // index. The value must already exist and be a string representation of a
32 // number.
33 void AddInt64ToListPref(size_t index,
34 int64 length,
35 base::ListValue* list_update) {
36 int64 value = 0;
37 std::string old_string_value;
38 bool rv = list_update->GetString(index, &old_string_value);
39 DCHECK(rv);
40 if (rv) {
41 rv = base::StringToInt64(old_string_value, &value);
42 DCHECK(rv);
44 value += length;
45 list_update->Set(index, new base::StringValue(base::Int64ToString(value)));
48 int64 ListPrefInt64Value(const base::ListValue& list_update, size_t index) {
49 std::string string_value;
50 if (!list_update.GetString(index, &string_value)) {
51 NOTREACHED();
52 return 0;
55 int64 value = 0;
56 bool rv = base::StringToInt64(string_value, &value);
57 DCHECK(rv);
58 return value;
61 // Report UMA metrics for daily data reductions.
62 void RecordDailyContentLengthHistograms(
63 int64 original_length,
64 int64 received_length,
65 int64 original_length_with_data_reduction_enabled,
66 int64 received_length_with_data_reduction_enabled,
67 int64 original_length_via_data_reduction_proxy,
68 int64 received_length_via_data_reduction_proxy,
69 int64 https_length_with_data_reduction_enabled,
70 int64 short_bypass_length_with_data_reduction_enabled,
71 int64 long_bypass_length_with_data_reduction_enabled,
72 int64 unknown_length_with_data_reduction_enabled) {
73 // Report daily UMA only for days having received content.
74 if (original_length <= 0 || received_length <= 0)
75 return;
77 // Record metrics in KB.
78 UMA_HISTOGRAM_COUNTS(
79 "Net.DailyOriginalContentLength", original_length >> 10);
80 UMA_HISTOGRAM_COUNTS(
81 "Net.DailyContentLength", received_length >> 10);
82 int percent = 0;
83 // UMA percentage cannot be negative.
84 if (original_length > received_length) {
85 percent = (100 * (original_length - received_length)) / original_length;
87 UMA_HISTOGRAM_PERCENTAGE("Net.DailyContentSavingPercent", percent);
89 if (original_length_with_data_reduction_enabled <= 0 ||
90 received_length_with_data_reduction_enabled <= 0) {
91 return;
94 UMA_HISTOGRAM_COUNTS(
95 "Net.DailyOriginalContentLength_DataReductionProxyEnabled",
96 original_length_with_data_reduction_enabled >> 10);
97 UMA_HISTOGRAM_COUNTS(
98 "Net.DailyContentLength_DataReductionProxyEnabled",
99 received_length_with_data_reduction_enabled >> 10);
101 int percent_data_reduction_proxy_enabled = 0;
102 // UMA percentage cannot be negative.
103 if (original_length_with_data_reduction_enabled >
104 received_length_with_data_reduction_enabled) {
105 percent_data_reduction_proxy_enabled =
106 100 * (original_length_with_data_reduction_enabled -
107 received_length_with_data_reduction_enabled) /
108 original_length_with_data_reduction_enabled;
110 UMA_HISTOGRAM_PERCENTAGE(
111 "Net.DailyContentSavingPercent_DataReductionProxyEnabled",
112 percent_data_reduction_proxy_enabled);
114 UMA_HISTOGRAM_PERCENTAGE(
115 "Net.DailyContentPercent_DataReductionProxyEnabled",
116 (100 * received_length_with_data_reduction_enabled) / received_length);
118 DCHECK_GE(https_length_with_data_reduction_enabled, 0);
119 UMA_HISTOGRAM_COUNTS(
120 "Net.DailyContentLength_DataReductionProxyEnabled_Https",
121 https_length_with_data_reduction_enabled >> 10);
122 UMA_HISTOGRAM_PERCENTAGE(
123 "Net.DailyContentPercent_DataReductionProxyEnabled_Https",
124 (100 * https_length_with_data_reduction_enabled) / received_length);
126 DCHECK_GE(short_bypass_length_with_data_reduction_enabled, 0);
127 UMA_HISTOGRAM_COUNTS(
128 "Net.DailyContentLength_DataReductionProxyEnabled_ShortBypass",
129 short_bypass_length_with_data_reduction_enabled >> 10);
130 UMA_HISTOGRAM_PERCENTAGE(
131 "Net.DailyContentPercent_DataReductionProxyEnabled_ShortBypass",
132 ((100 * short_bypass_length_with_data_reduction_enabled) /
133 received_length));
135 DCHECK_GE(long_bypass_length_with_data_reduction_enabled, 0);
136 UMA_HISTOGRAM_COUNTS(
137 "Net.DailyContentLength_DataReductionProxyEnabled_LongBypass",
138 long_bypass_length_with_data_reduction_enabled >> 10);
139 UMA_HISTOGRAM_PERCENTAGE(
140 "Net.DailyContentPercent_DataReductionProxyEnabled_LongBypass",
141 ((100 * long_bypass_length_with_data_reduction_enabled) /
142 received_length));
144 DCHECK_GE(unknown_length_with_data_reduction_enabled, 0);
145 UMA_HISTOGRAM_COUNTS(
146 "Net.DailyContentLength_DataReductionProxyEnabled_Unknown",
147 unknown_length_with_data_reduction_enabled >> 10);
148 UMA_HISTOGRAM_PERCENTAGE(
149 "Net.DailyContentPercent_DataReductionProxyEnabled_Unknown",
150 ((100 * unknown_length_with_data_reduction_enabled) /
151 received_length));
153 DCHECK_GE(original_length_via_data_reduction_proxy, 0);
154 UMA_HISTOGRAM_COUNTS(
155 "Net.DailyOriginalContentLength_ViaDataReductionProxy",
156 original_length_via_data_reduction_proxy >> 10);
157 DCHECK_GE(received_length_via_data_reduction_proxy, 0);
158 UMA_HISTOGRAM_COUNTS(
159 "Net.DailyContentLength_ViaDataReductionProxy",
160 received_length_via_data_reduction_proxy >> 10);
161 int percent_via_data_reduction_proxy = 0;
162 if (original_length_via_data_reduction_proxy >
163 received_length_via_data_reduction_proxy) {
164 percent_via_data_reduction_proxy =
165 100 * (original_length_via_data_reduction_proxy -
166 received_length_via_data_reduction_proxy) /
167 original_length_via_data_reduction_proxy;
169 UMA_HISTOGRAM_PERCENTAGE(
170 "Net.DailyContentSavingPercent_ViaDataReductionProxy",
171 percent_via_data_reduction_proxy);
172 UMA_HISTOGRAM_PERCENTAGE(
173 "Net.DailyContentPercent_ViaDataReductionProxy",
174 (100 * received_length_via_data_reduction_proxy) / received_length);
177 // Ensure list has exactly |length| elements, either by truncating at the
178 // front, or appending "0"'s to the back.
179 void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t length) {
180 // Remove data for old days from the front.
181 while (list->GetSize() > length)
182 list->Remove(0, NULL);
183 // Newly added lists are empty. Add entries to back to fill the window,
184 // each initialized to zero.
185 while (list->GetSize() < length)
186 list->AppendString(base::Int64ToString(0));
187 DCHECK_EQ(length, list->GetSize());
190 // DailyContentLengthUpdate maintains a data saving pref. The pref is a list
191 // of |kNumDaysInHistory| elements of daily total content lengths for the past
192 // |kNumDaysInHistory| days.
193 class DailyContentLengthUpdate {
194 public:
195 DailyContentLengthUpdate(
196 const char* pref,
197 PrefService* pref_service)
198 : update_(pref_service, pref) {
201 void UpdateForDataChange(int days_since_last_update) {
202 // New empty lists may have been created. Maintain the invariant that
203 // there should be exactly |kNumDaysInHistory| days in the histories.
204 MaintainContentLengthPrefsWindow(update_.Get(), kNumDaysInHistory);
205 if (days_since_last_update) {
206 MaintainContentLengthPrefForDateChange(days_since_last_update);
210 // Update the lengths for the current day.
211 void Add(int content_length) {
212 AddInt64ToListPref(kNumDaysInHistory - 1, content_length, update_.Get());
215 int64 GetListPrefValue(size_t index) {
216 return ListPrefInt64Value(*update_, index);
219 private:
220 // Update the list for date change and ensure the list has exactly |length|
221 // elements. The last entry in the list will be for the current day after
222 // the update.
223 void MaintainContentLengthPrefForDateChange(int days_since_last_update) {
224 if (days_since_last_update == -1) {
225 // The system may go backwards in time by up to a day for legitimate
226 // reasons, such as with changes to the time zone. In such cases, we
227 // keep adding to the current day.
228 // Note: we accept the fact that some reported data is shifted to
229 // the adjacent day if users travel back and forth across time zones.
230 days_since_last_update = 0;
231 } else if (days_since_last_update < -1) {
232 // Erase all entries if the system went backwards in time by more than
233 // a day.
234 update_->Clear();
236 days_since_last_update = kNumDaysInHistory;
238 DCHECK_GE(days_since_last_update, 0);
240 // Add entries for days since last update event. This will make the
241 // lists longer than kNumDaysInHistory. The additional items will be cut off
242 // from the head of the lists by |MaintainContentLengthPrefsWindow|, below.
243 for (int i = 0;
244 i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory);
245 ++i) {
246 update_->AppendString(base::Int64ToString(0));
249 // Entries for new days may have been appended. Maintain the invariant that
250 // there should be exactly |kNumDaysInHistory| days in the histories.
251 MaintainContentLengthPrefsWindow(update_.Get(), kNumDaysInHistory);
254 ListPrefUpdate update_;
257 // DailyDataSavingUpdate maintains a pair of data saving prefs, original_update_
258 // and received_update_. pref_original is a list of |kNumDaysInHistory| elements
259 // of daily total original content lengths for the past |kNumDaysInHistory|
260 // days. pref_received is the corresponding list of the daily total received
261 // content lengths.
262 class DailyDataSavingUpdate {
263 public:
264 DailyDataSavingUpdate(
265 const char* pref_original,
266 const char* pref_received,
267 PrefService* pref_service)
268 : original_(pref_original, pref_service),
269 received_(pref_received, pref_service) {
272 void UpdateForDataChange(int days_since_last_update) {
273 original_.UpdateForDataChange(days_since_last_update);
274 received_.UpdateForDataChange(days_since_last_update);
277 // Update the lengths for the current day.
278 void Add(int original_content_length, int received_content_length) {
279 original_.Add(original_content_length);
280 received_.Add(received_content_length);
283 int64 GetOriginalListPrefValue(size_t index) {
284 return original_.GetListPrefValue(index);
286 int64 GetReceivedListPrefValue(size_t index) {
287 return received_.GetListPrefValue(index);
290 private:
291 DailyContentLengthUpdate original_;
292 DailyContentLengthUpdate received_;
295 } // namespace
297 DataReductionProxyRequestType GetDataReductionProxyRequestType(
298 const net::URLRequest* request) {
299 if (request->url().SchemeIs("https"))
300 return HTTPS;
301 if (!request->url().SchemeIs("http")) {
302 NOTREACHED();
303 return UNKNOWN_TYPE;
305 #if defined(SPDY_PROXY_AUTH_ORIGIN)
306 DataReductionProxyParams params(
307 DataReductionProxyParams::kAllowed |
308 DataReductionProxyParams::kFallbackAllowed |
309 DataReductionProxyParams::kPromoAllowed);
310 base::TimeDelta bypass_delay;
311 if (params.AreDataReductionProxiesBypassed(*request, &bypass_delay)) {
312 if (bypass_delay > base::TimeDelta::FromSeconds(kLongBypassDelayInSeconds))
313 return LONG_BYPASS;
314 return SHORT_BYPASS;
316 #endif
317 if (request->response_info().headers &&
318 HasDataReductionProxyViaHeader(request->response_info().headers, NULL)) {
319 return VIA_DATA_REDUCTION_PROXY;
321 return UNKNOWN_TYPE;
324 int64 GetAdjustedOriginalContentLength(
325 DataReductionProxyRequestType request_type,
326 int64 original_content_length,
327 int64 received_content_length) {
328 // Since there was no indication of the original content length, presume
329 // it is no different from the number of bytes read.
330 if (original_content_length == -1 ||
331 request_type != VIA_DATA_REDUCTION_PROXY) {
332 return received_content_length;
334 return original_content_length;
337 void UpdateContentLengthPrefsForDataReductionProxy(
338 int received_content_length,
339 int original_content_length,
340 bool with_data_reduction_proxy_enabled,
341 DataReductionProxyRequestType request_type,
342 base::Time now, PrefService* prefs) {
343 // TODO(bengr): Remove this check once the underlying cause of
344 // http://crbug.com/287821 is fixed. For now, only continue if the current
345 // year is reported as being between 1972 and 2970.
346 base::TimeDelta time_since_unix_epoch = now - base::Time::UnixEpoch();
347 const int kMinDaysSinceUnixEpoch = 365 * 2; // 2 years.
348 const int kMaxDaysSinceUnixEpoch = 365 * 1000; // 1000 years.
349 if (time_since_unix_epoch.InDays() < kMinDaysSinceUnixEpoch ||
350 time_since_unix_epoch.InDays() > kMaxDaysSinceUnixEpoch) {
351 return;
354 // Determine how many days it has been since the last update.
355 int64 then_internal = prefs->GetInt64(
356 data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate);
358 #if defined(OS_WIN)
359 base::Time then_midnight = base::Time::FromInternalValue(then_internal);
360 base::Time midnight =
361 base::Time::FromInternalValue(
362 (now.ToInternalValue() / base::Time::kMicrosecondsPerDay) *
363 base::Time::kMicrosecondsPerDay);
364 #else
365 // Local midnight could have been shifted due to time zone change.
366 base::Time then_midnight =
367 base::Time::FromInternalValue(then_internal).LocalMidnight();
368 base::Time midnight = now.LocalMidnight();
369 #endif
371 int days_since_last_update = (midnight - then_midnight).InDays();
373 // Each day, we calculate the total number of bytes received and the total
374 // size of all corresponding resources before any data-reducing recompression
375 // is applied. These values are used to compute the data savings realized
376 // by applying our compression techniques. Totals for the last
377 // |kNumDaysInHistory| days are maintained.
378 DailyDataSavingUpdate total(
379 data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
380 data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
381 prefs);
382 total.UpdateForDataChange(days_since_last_update);
384 DailyDataSavingUpdate proxy_enabled(
385 data_reduction_proxy::prefs::
386 kDailyOriginalContentLengthWithDataReductionProxyEnabled,
387 data_reduction_proxy::prefs::
388 kDailyContentLengthWithDataReductionProxyEnabled,
389 prefs);
390 proxy_enabled.UpdateForDataChange(days_since_last_update);
392 DailyDataSavingUpdate via_proxy(
393 data_reduction_proxy::prefs::
394 kDailyOriginalContentLengthViaDataReductionProxy,
395 data_reduction_proxy::prefs::
396 kDailyContentLengthViaDataReductionProxy,
397 prefs);
398 via_proxy.UpdateForDataChange(days_since_last_update);
400 DailyContentLengthUpdate https(
401 data_reduction_proxy::prefs::
402 kDailyContentLengthHttpsWithDataReductionProxyEnabled,
403 prefs);
404 https.UpdateForDataChange(days_since_last_update);
406 DailyContentLengthUpdate short_bypass(
407 data_reduction_proxy::prefs::
408 kDailyContentLengthShortBypassWithDataReductionProxyEnabled,
409 prefs);
410 short_bypass.UpdateForDataChange(days_since_last_update);
412 DailyContentLengthUpdate long_bypass(
413 data_reduction_proxy::prefs::
414 kDailyContentLengthLongBypassWithDataReductionProxyEnabled,
415 prefs);
416 long_bypass.UpdateForDataChange(days_since_last_update);
418 DailyContentLengthUpdate unknown(
419 data_reduction_proxy::prefs::
420 kDailyContentLengthUnknownWithDataReductionProxyEnabled,
421 prefs);
422 unknown.UpdateForDataChange(days_since_last_update);
424 total.Add(original_content_length, received_content_length);
425 if (with_data_reduction_proxy_enabled) {
426 proxy_enabled.Add(original_content_length, received_content_length);
427 // Ignore data source cases, if exist, when
428 // "with_data_reduction_proxy_enabled == false"
429 switch (request_type) {
430 case VIA_DATA_REDUCTION_PROXY:
431 via_proxy.Add(original_content_length, received_content_length);
432 break;
433 case HTTPS:
434 https.Add(received_content_length);
435 break;
436 case SHORT_BYPASS:
437 short_bypass.Add(received_content_length);
438 break;
439 case LONG_BYPASS:
440 long_bypass.Add(received_content_length);
441 break;
442 case UNKNOWN_TYPE:
443 unknown.Add(received_content_length);
444 break;
448 if (days_since_last_update) {
449 // Record the last update time in microseconds in UTC.
450 prefs->SetInt64(
451 data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate,
452 midnight.ToInternalValue());
454 // A new day. Report the previous day's data if exists. We'll lose usage
455 // data if the last time Chrome was run was more than a day ago.
456 // Here, we prefer collecting less data but the collected data is
457 // associated with an accurate date.
458 if (days_since_last_update == 1) {
459 // The previous day's data point is the second one from the tail.
460 // Therefore (kNumDaysInHistory - 2) below.
461 RecordDailyContentLengthHistograms(
462 total.GetOriginalListPrefValue(kNumDaysInHistory - 2),
463 total.GetReceivedListPrefValue(kNumDaysInHistory - 2),
464 proxy_enabled.GetOriginalListPrefValue(kNumDaysInHistory - 2),
465 proxy_enabled.GetReceivedListPrefValue(kNumDaysInHistory - 2),
466 via_proxy.GetOriginalListPrefValue(kNumDaysInHistory - 2),
467 via_proxy.GetReceivedListPrefValue(kNumDaysInHistory - 2),
468 https.GetListPrefValue(kNumDaysInHistory - 2),
469 short_bypass.GetListPrefValue(kNumDaysInHistory - 2),
470 long_bypass.GetListPrefValue(kNumDaysInHistory - 2),
471 unknown.GetListPrefValue(kNumDaysInHistory - 2));
476 void UpdateContentLengthPrefs(
477 int received_content_length,
478 int original_content_length,
479 bool with_data_reduction_proxy_enabled,
480 DataReductionProxyRequestType request_type,
481 PrefService* prefs) {
482 int64 total_received = prefs->GetInt64(
483 data_reduction_proxy::prefs::kHttpReceivedContentLength);
484 int64 total_original = prefs->GetInt64(
485 data_reduction_proxy::prefs::kHttpOriginalContentLength);
486 total_received += received_content_length;
487 total_original += original_content_length;
488 prefs->SetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength,
489 total_received);
490 prefs->SetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength,
491 total_original);
493 UpdateContentLengthPrefsForDataReductionProxy(
494 received_content_length,
495 original_content_length,
496 with_data_reduction_proxy_enabled,
497 request_type,
498 base::Time::Now(),
499 prefs);
502 } // namespace data_reduction_proxy