diff options
20 files changed, 353 insertions, 136 deletions
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc index 1998bab..763d43a 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client.cc +++ b/chrome/browser/metrics/chrome_metrics_service_client.cc @@ -4,6 +4,8 @@ #include "chrome/browser/metrics/chrome_metrics_service_client.h" +#include <vector> + #include "base/bind.h" #include "base/callback.h" #include "base/command_line.h" @@ -26,6 +28,7 @@ #include "chrome/common/chrome_version_info.h" #include "chrome/common/crash_keys.h" #include "chrome/common/render_messages.h" +#include "components/metrics/net/net_metrics_log_uploader.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/histogram_fetcher.h" #include "content/public/browser/notification_service.h" @@ -182,6 +185,17 @@ void ChromeMetricsServiceClient::OnLogUploadComplete() { network_stats_uploader_.CollectAndReportNetworkStats(); } +void ChromeMetricsServiceClient::StartGatheringMetrics( + const base::Closure& done_callback) { +// TODO(blundell): Move all metrics gathering tasks from MetricsService to +// here. +#if defined(OS_CHROMEOS) + chromeos_metrics_provider_->InitTaskGetHardwareClass(done_callback); +#else + done_callback.Run(); +#endif +} + void ChromeMetricsServiceClient::CollectFinalMetrics( const base::Closure& done_callback) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -212,6 +226,17 @@ void ChromeMetricsServiceClient::CollectFinalMetrics( } } +scoped_ptr<metrics::MetricsLogUploader> +ChromeMetricsServiceClient::CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) { + return scoped_ptr<metrics::MetricsLogUploader>( + new metrics::NetMetricsLogUploader( + g_browser_process->system_request_context(), server_url, mime_type, + on_upload_complete)); +} + void ChromeMetricsServiceClient::OnMemoryDetailCollectionDone() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -335,17 +360,6 @@ void ChromeMetricsServiceClient::Observe( } } -void ChromeMetricsServiceClient::StartGatheringMetrics( - const base::Closure& done_callback) { -// TODO(blundell): Move all metrics gathering tasks from MetricsService to -// here. -#if defined(OS_CHROMEOS) - chromeos_metrics_provider_->InitTaskGetHardwareClass(done_callback); -#else - done_callback.Run(); -#endif -} - #if defined(OS_WIN) void ChromeMetricsServiceClient::CountBrowserCrashDumpAttempts() { // Open the registry key for iteration. diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h index aef2120..aba5945 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client.h +++ b/chrome/browser/metrics/chrome_metrics_service_client.h @@ -48,6 +48,10 @@ class ChromeMetricsServiceClient : public metrics::MetricsServiceClient, const base::Closure& done_callback) OVERRIDE; virtual void CollectFinalMetrics(const base::Closure& done_callback) OVERRIDE; + virtual scoped_ptr<metrics::MetricsLogUploader> CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) OVERRIDE; MetricsService* metrics_service() { return metrics_service_.get(); } diff --git a/chrome/browser/metrics/compression_utils.h b/chrome/browser/metrics/compression_utils.h deleted file mode 100644 index ec208ec..0000000 --- a/chrome/browser/metrics/compression_utils.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_METRICS_COMPRESSION_UTILS_H_ -#define CHROME_BROWSER_METRICS_COMPRESSION_UTILS_H_ - -#include <string> - -namespace chrome { - -// Compresses the text in |input| using gzip storing the result in |output|. -bool GzipCompress(const std::string& input, std::string* output); - -} // namespace chrome - -#endif // CHROME_BROWSER_METRICS_COMPRESSION_UTILS_H_ diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index b12aae4..c616651 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -185,7 +185,6 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/metrics/chrome_stability_metrics_provider.h" -#include "chrome/browser/metrics/compression_utils.h" #include "chrome/browser/metrics/gpu_metrics_provider.h" #include "chrome/browser/metrics/metrics_log.h" #include "chrome/browser/metrics/metrics_state_manager.h" @@ -196,12 +195,11 @@ #include "chrome/common/variations/variations_util.h" #include "components/metrics/metrics_log_base.h" #include "components/metrics/metrics_log_manager.h" +#include "components/metrics/metrics_log_uploader.h" #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_reporting_scheduler.h" #include "components/metrics/metrics_service_client.h" #include "components/variations/entropy_provider.h" -#include "net/base/load_flags.h" -#include "net/url_request/url_fetcher.h" #if defined(ENABLE_PLUGINS) // TODO(asvitkine): Move this out of MetricsService. @@ -270,12 +268,12 @@ enum ResponseStatus { ResponseStatus ResponseCodeToStatus(int response_code) { switch (response_code) { + case -1: + return NO_RESPONSE; case 200: return SUCCESS; case 400: return BAD_REQUEST; - case net::URLFetcher::RESPONSE_CODE_INVALID: - return NO_RESPONSE; default: return UNKNOWN_FAILURE; } @@ -371,11 +369,11 @@ MetricsService::MetricsService(metrics::MetricsStateManager* state_manager, test_mode_active_(false), state_(INITIALIZED), has_initial_stability_log_(false), + log_upload_in_progress_(false), idle_since_last_transmission_(false), session_id_(-1), self_ptr_factory_(this), - state_saver_factory_(this), - waiting_for_asynchronous_reporting_step_(false) { + state_saver_factory_(this) { DCHECK(IsSingleThreaded()); DCHECK(state_manager_); DCHECK(client_); @@ -885,7 +883,7 @@ void MetricsService::PushPendingLogsToPersistentStorage() { if (log_manager_.has_staged_log()) { // We may race here, and send second copy of the log later. metrics::PersistedLogs::StoreType store_type; - if (current_fetch_.get()) + if (log_upload_in_progress_) store_type = metrics::PersistedLogs::PROVISIONAL_STORE; else store_type = metrics::PersistedLogs::NORMAL_STORE; @@ -960,11 +958,11 @@ void MetricsService::StartScheduledUpload() { } void MetricsService::OnFinalLogInfoCollectionDone() { - // If somehow there is a fetch in progress, we return and hope things work - // out. The scheduler isn't informed since if this happens, the scheduler + // If somehow there is a log upload in progress, we return and hope things + // work out. The scheduler isn't informed since if this happens, the scheduler // will get a response from the upload. - DCHECK(!current_fetch_.get()); - if (current_fetch_.get()) + DCHECK(!log_upload_in_progress_); + if (log_upload_in_progress_) return; // Abort if metrics were turned off during the final info gathering. @@ -1111,78 +1109,39 @@ void MetricsService::PrepareInitialMetricsLog() { void MetricsService::SendStagedLog() { DCHECK(log_manager_.has_staged_log()); + if (!log_manager_.has_staged_log()) + return; - PrepareFetchWithStagedLog(); + DCHECK(!log_upload_in_progress_); + log_upload_in_progress_ = true; - bool upload_created = (current_fetch_.get() != NULL); - UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created); - if (!upload_created) { - // Compression failed, and log discarded :-/. + if (!log_uploader_) { + log_uploader_ = client_->CreateUploader( + kServerUrl, kMimeType, + base::Bind(&MetricsService::OnLogUploadComplete, + self_ptr_factory_.GetWeakPtr())); + } + + const std::string hash = + base::HexEncode(log_manager_.staged_log_hash().data(), + log_manager_.staged_log_hash().size()); + bool success = log_uploader_->UploadLog(log_manager_.staged_log(), hash); + UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", success); + if (!success) { // Skip this upload and hope things work out next time. log_manager_.DiscardStagedLog(); scheduler_->UploadCancelled(); + log_upload_in_progress_ = false; return; } - DCHECK(!waiting_for_asynchronous_reporting_step_); - waiting_for_asynchronous_reporting_step_ = true; - - current_fetch_->Start(); - HandleIdleSinceLastTransmission(true); } -void MetricsService::PrepareFetchWithStagedLog() { - DCHECK(log_manager_.has_staged_log()); - - // Prepare the protobuf version. - DCHECK(!current_fetch_.get()); - if (log_manager_.has_staged_log()) { - current_fetch_.reset(net::URLFetcher::Create( - GURL(kServerUrl), net::URLFetcher::POST, this)); - current_fetch_->SetRequestContext( - g_browser_process->system_request_context()); - - std::string log_text = log_manager_.staged_log(); - std::string compressed_log_text; - bool compression_successful = chrome::GzipCompress(log_text, - &compressed_log_text); - DCHECK(compression_successful); - if (compression_successful) { - current_fetch_->SetUploadData(kMimeType, compressed_log_text); - // Tell the server that we're uploading gzipped protobufs. - current_fetch_->SetExtraRequestHeaders("content-encoding: gzip"); - const std::string hash = - base::HexEncode(log_manager_.staged_log_hash().data(), - log_manager_.staged_log_hash().size()); - DCHECK(!hash.empty()); - current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash); - UMA_HISTOGRAM_PERCENTAGE( - "UMA.ProtoCompressionRatio", - 100 * compressed_log_text.size() / log_text.size()); - UMA_HISTOGRAM_CUSTOM_COUNTS( - "UMA.ProtoGzippedKBSaved", - (log_text.size() - compressed_log_text.size()) / 1024, - 1, 2000, 50); - } - - // We already drop cookies server-side, but we might as well strip them out - // client-side as well. - current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_COOKIES); - } -} - -void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) { - DCHECK(waiting_for_asynchronous_reporting_step_); - // We're not allowed to re-use the existing |URLFetcher|s, so free them here. - // Note however that |source| is aliased to the fetcher, so we should be - // careful not to delete it too early. - DCHECK_EQ(current_fetch_.get(), source); - scoped_ptr<net::URLFetcher> s(current_fetch_.Pass()); - - int response_code = source->GetResponseCode(); +void MetricsService::OnLogUploadComplete(int response_code) { + DCHECK(log_upload_in_progress_); + log_upload_in_progress_ = false; // Log a histogram to track response success vs. failure rates. UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf", @@ -1210,8 +1169,6 @@ void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) { if (upload_succeeded || discard_log) log_manager_.DiscardStagedLog(); - waiting_for_asynchronous_reporting_step_ = false; - if (!log_manager_.has_staged_log()) { switch (state_) { case SENDING_INITIAL_STABILITY_LOG: diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h index 705392f..116fadf 100644 --- a/chrome/browser/metrics/metrics_service.h +++ b/chrome/browser/metrics/metrics_service.h @@ -32,7 +32,6 @@ #include "components/metrics/metrics_provider.h" #include "components/metrics/metrics_service_observer.h" #include "components/variations/active_field_trials.h" -#include "net/url_request/url_fetcher_delegate.h" class GoogleUpdateMetricsProviderWin; class MetricsReportingScheduler; @@ -55,6 +54,7 @@ namespace content { } namespace metrics { +class MetricsLogUploader; class MetricsServiceClient; class MetricsStateManager; } @@ -89,8 +89,7 @@ struct SyntheticTrialGroup { class MetricsService : public base::HistogramFlattener, - public chrome_browser_metrics::TrackingSynchronizerObserver, - public net::URLFetcherDelegate { + public chrome_browser_metrics::TrackingSynchronizerObserver { public: // The execution phase of the browser. enum ExecutionPhase { @@ -357,14 +356,8 @@ class MetricsService // Uploads the currently staged log (which must be non-null). void SendStagedLog(); - // Prepared the staged log to be passed to the server. Upon return, - // current_fetch_ should be reset with its upload data set to a compressed - // copy of the staged log. - void PrepareFetchWithStagedLog(); - - // Implementation of net::URLFetcherDelegate. Called after transmission - // completes (either successfully or with failure). - virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; + // Called after transmission completes (either successfully or with failure). + void OnLogUploadComplete(int response_code); // Reads, increments and then sets the specified integer preference. void IncrementPrefValue(const char* path); @@ -453,8 +446,11 @@ class MetricsService // initial stability log may be sent before this. scoped_ptr<MetricsLog> initial_metrics_log_; - // The outstanding transmission appears as a URL Fetch operation. - scoped_ptr<net::URLFetcher> current_fetch_; + // Instance of the helper class for uploading logs. + scoped_ptr<metrics::MetricsLogUploader> log_uploader_; + + // Whether there is a current log upload in progress. + bool log_upload_in_progress_; // Whether the MetricsService object has received any notifications since // the last time a transmission was sent. @@ -474,10 +470,6 @@ class MetricsService // The scheduler for determining when uploads should happen. scoped_ptr<MetricsReportingScheduler> scheduler_; - // Indicates that an asynchronous reporting step is running. - // This is used only for debugging. - bool waiting_for_asynchronous_reporting_step_; - // Stores the time of the first call to |GetUptimes()|. base::TimeTicks first_updated_time_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b7288d58..bc33485 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -43,6 +43,7 @@ '../components/components.gyp:infobars_core', '../components/components.gyp:invalidation', '../components/components.gyp:metrics', + '../components/components.gyp:metrics_net', '../components/components.gyp:navigation_metrics', '../components/components.gyp:os_crypt', '../components/components.gyp:password_manager_core_browser', @@ -1210,8 +1211,6 @@ 'browser/metrics/chrome_metrics_service_client.h', 'browser/metrics/chrome_stability_metrics_provider.cc', 'browser/metrics/chrome_stability_metrics_provider.h', - 'browser/metrics/compression_utils.cc', - 'browser/metrics/compression_utils.h', 'browser/metrics/extensions_metrics_provider.cc', 'browser/metrics/extensions_metrics_provider.h', 'browser/metrics/field_trial_synchronizer.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index f30f6f8..5894c64 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1091,7 +1091,6 @@ 'browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc', 'browser/metrics/chrome_metrics_service_accessor_unittest.cc', 'browser/metrics/cloned_install_detector_unittest.cc', - 'browser/metrics/compression_utils_unittest.cc', 'browser/metrics/extensions_metrics_provider_unittest.cc', 'browser/metrics/gpu_metrics_provider_unittest.cc', 'browser/metrics/metrics_log_unittest.cc', diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 0674d26..56dd758 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -111,6 +111,7 @@ 'metrics/metrics_log_base_unittest.cc', 'metrics/metrics_log_manager_unittest.cc', 'metrics/metrics_reporting_scheduler_unittest.cc', + 'metrics/net/compression_utils_unittest.cc', 'metrics/persisted_logs_unittest.cc', 'navigation_interception/intercept_navigation_resource_throttle_unittest.cc', 'os_crypt/ie7_password_win_unittest.cc', @@ -263,6 +264,10 @@ # Dependencies of language_usage_metrics 'components.gyp:language_usage_metrics', + # Dependencies of metrics + 'components.gyp:metrics', + 'components.gyp:metrics_net', + # Dependencies of os_crypt 'components.gyp:os_crypt', diff --git a/components/metrics.gypi b/components/metrics.gypi index fd79d50..f9896fb 100644 --- a/components/metrics.gypi +++ b/components/metrics.gypi @@ -25,6 +25,8 @@ 'metrics/metrics_hashes.h', 'metrics/metrics_log_base.cc', 'metrics/metrics_log_base.h', + 'metrics/metrics_log_uploader.cc', + 'metrics/metrics_log_uploader.h', 'metrics/metrics_log_manager.cc', 'metrics/metrics_log_manager.h', 'metrics/metrics_pref_names.cc', @@ -51,6 +53,24 @@ ], }, { + 'target_name': 'metrics_net', + 'type': 'static_library', + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../net/net.gyp:net', + '../third_party/zlib/zlib.gyp:zlib', + 'metrics', + ], + 'sources': [ + 'metrics/net/compression_utils.cc', + 'metrics/net/compression_utils.h', + 'metrics/net/net_metrics_log_uploader.cc', + 'metrics/net/net_metrics_log_uploader.h', + ], + }, + { # Protobuf compiler / generator for UMA (User Metrics Analysis). 'target_name': 'component_metrics_proto', 'type': 'static_library', diff --git a/components/metrics/metrics_log_uploader.cc b/components/metrics/metrics_log_uploader.cc new file mode 100644 index 0000000..41b83ed --- /dev/null +++ b/components/metrics/metrics_log_uploader.cc @@ -0,0 +1,21 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/metrics_log_uploader.h" + +namespace metrics { + +MetricsLogUploader::MetricsLogUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) + : server_url_(server_url), + mime_type_(mime_type), + on_upload_complete_(on_upload_complete) { +} + +MetricsLogUploader::~MetricsLogUploader() { +} + +} // namespace metrics diff --git a/components/metrics/metrics_log_uploader.h b/components/metrics/metrics_log_uploader.h new file mode 100644 index 0000000..0deecc8 --- /dev/null +++ b/components/metrics/metrics_log_uploader.h @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_METRICS_METRICS_LOG_UPLOADER_H_ +#define COMPONENTS_METRICS_METRICS_LOG_UPLOADER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/macros.h" + +namespace metrics { + +// MetricsLogUploader is an abstract base class for uploading UMA logs on behalf +// of MetricsService. +class MetricsLogUploader { + public: + // Constructs the uploader that will upload logs to the specified |server_url| + // with the given |mime_type|. The |on_upload_complete| callback will be + // called with the HTTP response code of the upload or with -1 on an error. + MetricsLogUploader(const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete); + virtual ~MetricsLogUploader(); + + // Uploads a log with the specified |log_data| and |log_hash|. |log_hash| is + // expected to be the hex-encoded SHA1 hash of |log_data|. + virtual bool UploadLog(const std::string& log_data, + const std::string& log_hash) = 0; + + protected: + const std::string server_url_; + const std::string mime_type_; + const base::Callback<void(int)> on_upload_complete_; + + private: + DISALLOW_COPY_AND_ASSIGN(MetricsLogUploader); +}; + +} // namespace metrics + +#endif // COMPONENTS_METRICS_METRICS_LOG_UPLOADER_H_ diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h index dbad4a3..1fcfb6e 100644 --- a/components/metrics/metrics_service_client.h +++ b/components/metrics/metrics_service_client.h @@ -9,10 +9,13 @@ #include "base/basictypes.h" #include "base/callback_forward.h" +#include "base/memory/scoped_ptr.h" #include "components/metrics/proto/system_profile.pb.h" namespace metrics { +class MetricsLogUploader; + // An abstraction of operations that depend on the embedder's (e.g. Chrome) // environment. class MetricsServiceClient { @@ -50,6 +53,13 @@ class MetricsServiceClient { // extra histograms that will go in that log. Asynchronous API - the client // implementation should call |done_callback| when complete. virtual void CollectFinalMetrics(const base::Closure& done_callback) = 0; + + // Creates a MetricsLogUploader with the specified parameters (see comments on + // MetricsLogUploader for details). + virtual scoped_ptr<MetricsLogUploader> CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) = 0; }; } // namespace metrics diff --git a/components/metrics/net/DEPS b/components/metrics/net/DEPS new file mode 100644 index 0000000..71ea427 --- /dev/null +++ b/components/metrics/net/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+net", + "+third_party/zlib", +] diff --git a/chrome/browser/metrics/compression_utils.cc b/components/metrics/net/compression_utils.cc index 71f68ab..e8efe18 100644 --- a/chrome/browser/metrics/compression_utils.cc +++ b/components/metrics/net/compression_utils.cc @@ -1,8 +1,8 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/metrics/compression_utils.h" +#include "components/metrics/net/compression_utils.h" #include <vector> @@ -62,31 +62,35 @@ int GzipCompressHelper(Bytef* dest, err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; } *dest_length = stream.total_out; err = deflateEnd(&stream); return err; } + } // namespace -namespace chrome { +namespace metrics { bool GzipCompress(const std::string& input, std::string* output) { + const uLongf input_size = static_cast<uLongf>(input.size()); std::vector<Bytef> compressed_data(kGzipZlibHeaderDifferenceBytes + - compressBound(input.size())); + compressBound(input_size)); - uLongf compressed_size = compressed_data.size(); + uLongf compressed_size = static_cast<uLongf>(compressed_data.size()); if (GzipCompressHelper(&compressed_data.front(), &compressed_size, bit_cast<const Bytef*>(input.data()), - input.size()) != Z_OK) + input_size) != Z_OK) { return false; + } compressed_data.resize(compressed_size); output->assign(compressed_data.begin(), compressed_data.end()); return true; } -} // namespace chrome + +} // namespace metrics diff --git a/components/metrics/net/compression_utils.h b/components/metrics/net/compression_utils.h new file mode 100644 index 0000000..ee875dd --- /dev/null +++ b/components/metrics/net/compression_utils.h @@ -0,0 +1,17 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_METRICS_NET_COMPRESSION_UTILS_H_ +#define COMPONENTS_METRICS_NET_COMPRESSION_UTILS_H_ + +#include <string> + +namespace metrics { + +// Compresses the text in |input| using gzip, storing the result in |output|. +bool GzipCompress(const std::string& input, std::string* output); + +} // namespace metrics + +#endif // COMPONENTS_METRICS_NET_COMPRESSION_UTILS_H_ diff --git a/chrome/browser/metrics/compression_utils_unittest.cc b/components/metrics/net/compression_utils_unittest.cc index ad05eef..05305d4 100644 --- a/chrome/browser/metrics/compression_utils_unittest.cc +++ b/components/metrics/net/compression_utils_unittest.cc @@ -1,17 +1,19 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/metrics/net/compression_utils.h" + #include <string> #include "base/base_paths.h" #include "base/basictypes.h" #include "base/file_util.h" #include "base/path_service.h" -#include "chrome/browser/metrics/compression_utils.h" -#include "chrome/common/chrome_paths.h" #include "testing/gtest/include/gtest/gtest.h" +namespace metrics { + namespace { // The data to be compressed by gzip. This is the hex representation of "hello @@ -35,14 +37,16 @@ const uint8 kCompressedData[] = #pragma warning( default: 4309 ) #endif +} // namespace + TEST(CompressionUtilsTest, GzipCompression) { std::string data(reinterpret_cast<const char*>(kData), arraysize(kData)); std::string compressed_data; - EXPECT_TRUE(chrome::GzipCompress(data, &compressed_data)); + EXPECT_TRUE(GzipCompress(data, &compressed_data)); std::string golden_compressed_data( reinterpret_cast<const char*>(kCompressedData), arraysize(kCompressedData)); EXPECT_EQ(golden_compressed_data, compressed_data); } -} // namespace +} // namespace metrics diff --git a/components/metrics/net/net_metrics_log_uploader.cc b/components/metrics/net/net_metrics_log_uploader.cc new file mode 100644 index 0000000..09042bd --- /dev/null +++ b/components/metrics/net/net_metrics_log_uploader.cc @@ -0,0 +1,74 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/net/net_metrics_log_uploader.h" + +#include "base/metrics/histogram.h" +#include "components/metrics/net/compression_utils.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_fetcher.h" +#include "url/gurl.h" + +namespace metrics { + +NetMetricsLogUploader::NetMetricsLogUploader( + net::URLRequestContextGetter* request_context_getter, + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) + : MetricsLogUploader(server_url, mime_type, on_upload_complete), + request_context_getter_(request_context_getter) { +} + +NetMetricsLogUploader::~NetMetricsLogUploader() { +} + +bool NetMetricsLogUploader::UploadLog(const std::string& log_data, + const std::string& log_hash) { + std::string compressed_log_data; + if (!GzipCompress(log_data, &compressed_log_data)) { + NOTREACHED(); + return false; + } + + UMA_HISTOGRAM_PERCENTAGE( + "UMA.ProtoCompressionRatio", + static_cast<int>(100 * compressed_log_data.size() / log_data.size())); + UMA_HISTOGRAM_CUSTOM_COUNTS( + "UMA.ProtoGzippedKBSaved", + static_cast<int>((log_data.size() - compressed_log_data.size()) / 1024), + 1, 2000, 50); + + current_fetch_.reset( + net::URLFetcher::Create(GURL(server_url_), net::URLFetcher::POST, this)); + current_fetch_->SetRequestContext(request_context_getter_); + current_fetch_->SetUploadData(mime_type_, compressed_log_data); + + // Tell the server that we're uploading gzipped protobufs. + current_fetch_->SetExtraRequestHeaders("content-encoding: gzip"); + + DCHECK(!log_hash.empty()); + current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + log_hash); + + // We already drop cookies server-side, but we might as well strip them out + // client-side as well. + current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_DO_NOT_SEND_COOKIES); + return true; +} + +void NetMetricsLogUploader::OnURLFetchComplete(const net::URLFetcher* source) { + // We're not allowed to re-use the existing |URLFetcher|s, so free them here. + // Note however that |source| is aliased to the fetcher, so we should be + // careful not to delete it too early. + DCHECK_EQ(current_fetch_.get(), source); + + int response_code = source->GetResponseCode(); + if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) + response_code = -1; + on_upload_complete_.Run(response_code); + current_fetch_.reset(); +} + +} // namespace metrics diff --git a/components/metrics/net/net_metrics_log_uploader.h b/components/metrics/net/net_metrics_log_uploader.h new file mode 100644 index 0000000..4753fd7 --- /dev/null +++ b/components/metrics/net/net_metrics_log_uploader.h @@ -0,0 +1,54 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_METRICS_NET_NET_METRICS_LOG_UPLOADER_H_ +#define COMPONENTS_METRICS_NET_NET_METRICS_LOG_UPLOADER_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "components/metrics/metrics_log_uploader.h" +#include "net/url_request/url_fetcher_delegate.h" + +namespace net { +class URLFetcher; +class URLRequestContextGetter; +} + +namespace metrics { + +// Implementation of MetricsLogUploader using the Chrome network stack. +class NetMetricsLogUploader : public MetricsLogUploader, + public net::URLFetcherDelegate { + public: + // Constructs a NetMetricsLogUploader with the specified request context and + // other params (see comments on MetricsLogUploader for details). The caller + // must ensure that |request_context_getter| remains valid for the lifetime + // of this class. + NetMetricsLogUploader(net::URLRequestContextGetter* request_context_getter, + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete); + virtual ~NetMetricsLogUploader(); + + // MetricsLogUploader: + virtual bool UploadLog(const std::string& log_data, + const std::string& log_hash) OVERRIDE; + + private: + // net::URLFetcherDelegate: + virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; + + // The request context for fetches done using the network stack. + net::URLRequestContextGetter* const request_context_getter_; + + // The outstanding transmission appears as a URL Fetch operation. + scoped_ptr<net::URLFetcher> current_fetch_; + + DISALLOW_COPY_AND_ASSIGN(NetMetricsLogUploader); +}; + +} // namespace metrics + +#endif // COMPONENTS_METRICS_NET_NET_METRICS_LOG_UPLOADER_H_ diff --git a/components/metrics/test_metrics_service_client.cc b/components/metrics/test_metrics_service_client.cc index 891b90f..8d1b337 100644 --- a/components/metrics/test_metrics_service_client.cc +++ b/components/metrics/test_metrics_service_client.cc @@ -5,6 +5,7 @@ #include "components/metrics/test_metrics_service_client.h" #include "base/callback.h" +#include "components/metrics/metrics_log_uploader.h" namespace metrics { @@ -55,4 +56,11 @@ void TestMetricsServiceClient::CollectFinalMetrics( done_callback.Run(); } +scoped_ptr<MetricsLogUploader> TestMetricsServiceClient::CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) { + return scoped_ptr<MetricsLogUploader>(); +} + } // namespace metrics diff --git a/components/metrics/test_metrics_service_client.h b/components/metrics/test_metrics_service_client.h index b5b7ba9..407109d 100644 --- a/components/metrics/test_metrics_service_client.h +++ b/components/metrics/test_metrics_service_client.h @@ -32,6 +32,10 @@ class TestMetricsServiceClient : public MetricsServiceClient { const base::Closure& done_callback) OVERRIDE; virtual void CollectFinalMetrics(const base::Closure& done_callback) OVERRIDE; + virtual scoped_ptr<MetricsLogUploader> CreateUploader( + const std::string& server_url, + const std::string& mime_type, + const base::Callback<void(int)>& on_upload_complete) OVERRIDE; const std::string& get_client_id() const { return client_id_; } |