diff options
author | juyik@chromium.org <juyik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-16 21:41:44 +0000 |
---|---|---|
committer | juyik@chromium.org <juyik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-16 21:41:44 +0000 |
commit | 268d23f13de7d41e2dc42b90205fbd86a66676a0 (patch) | |
tree | 445afa9ef278cd1462bdab4eb13dd12c555dbe09 /google_apis/gcm | |
parent | e888193914dc13c6961a64c810852fd0d6268afb (diff) | |
download | chromium_src-268d23f13de7d41e2dc42b90205fbd86a66676a0.zip chromium_src-268d23f13de7d41e2dc42b90205fbd86a66676a0.tar.gz chromium_src-268d23f13de7d41e2dc42b90205fbd86a66676a0.tar.bz2 |
Add activity recording capability to gcm internals page. User can refresh, start/stop recording, and clear recording logs.
Also added more information to the device info section and fixed a bug there.
arv: owner review of chrome/browser/resources/*.
jianli & fgorski please review the rest of the code, and zea for owner review of these code.
BUG=341256
Review URL: https://codereview.chromium.org/202083005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264313 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'google_apis/gcm')
-rw-r--r-- | google_apis/gcm/engine/checkin_request.h | 1 | ||||
-rw-r--r-- | google_apis/gcm/engine/gcm_store.h | 9 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client.cc | 25 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client.h | 24 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client_unittest.cc | 11 | ||||
-rw-r--r-- | google_apis/gcm/gcm.gyp | 5 | ||||
-rw-r--r-- | google_apis/gcm/gcm_client.cc | 7 | ||||
-rw-r--r-- | google_apis/gcm/gcm_client.h | 13 | ||||
-rw-r--r-- | google_apis/gcm/gcm_client_impl.cc | 36 | ||||
-rw-r--r-- | google_apis/gcm/gcm_client_impl.h | 14 | ||||
-rw-r--r-- | google_apis/gcm/gcm_client_impl_unittest.cc | 18 | ||||
-rw-r--r-- | google_apis/gcm/monitoring/gcm_stats_recorder.cc | 150 | ||||
-rw-r--r-- | google_apis/gcm/monitoring/gcm_stats_recorder.h | 101 | ||||
-rw-r--r-- | google_apis/gcm/monitoring/gcm_stats_recorder_unittest.cc | 136 |
14 files changed, 522 insertions, 28 deletions
diff --git a/google_apis/gcm/engine/checkin_request.h b/google_apis/gcm/engine/checkin_request.h index 1d706a7..5ae8dd3 100644 --- a/google_apis/gcm/engine/checkin_request.h +++ b/google_apis/gcm/engine/checkin_request.h @@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "google_apis/gcm/base/gcm_export.h" +#include "google_apis/gcm/protocol/android_checkin.pb.h" #include "google_apis/gcm/protocol/checkin.pb.h" #include "net/base/backoff_entry.h" #include "net/url_request/url_fetcher_delegate.h" diff --git a/google_apis/gcm/engine/gcm_store.h b/google_apis/gcm/engine/gcm_store.h index 1b15e56b..8b9891d0 100644 --- a/google_apis/gcm/engine/gcm_store.h +++ b/google_apis/gcm/engine/gcm_store.h @@ -9,6 +9,8 @@ #include <string> #include <vector> +#include <google/protobuf/message_lite.h> + #include "base/basictypes.h" #include "base/callback_forward.h" #include "base/memory/linked_ptr.h" @@ -17,13 +19,6 @@ #include "base/time/time.h" #include "google_apis/gcm/base/gcm_export.h" #include "google_apis/gcm/engine/registration_info.h" -#include "google_apis/gcm/protocol/mcs.pb.h" - -namespace google { -namespace protobuf { -class MessageLite; -} // namespace protobuf -} // namespace google namespace gcm { diff --git a/google_apis/gcm/engine/mcs_client.cc b/google_apis/gcm/engine/mcs_client.cc index da8300c7..a99a333 100644 --- a/google_apis/gcm/engine/mcs_client.cc +++ b/google_apis/gcm/engine/mcs_client.cc @@ -15,6 +15,7 @@ #include "google_apis/gcm/base/mcs_util.h" #include "google_apis/gcm/base/socket_stream.h" #include "google_apis/gcm/engine/connection_factory.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" using namespace google::protobuf::io; @@ -128,6 +129,14 @@ ReliablePacketInfo::ReliablePacketInfo() } ReliablePacketInfo::~ReliablePacketInfo() {} +int MCSClient::GetSendQueueSize() const { + return to_send_.size(); +} + +int MCSClient::GetResendQueueSize() const { + return to_resend_.size(); +} + std::string MCSClient::GetStateString() const { switch(state_) { case UNINITIALIZED: @@ -147,7 +156,8 @@ std::string MCSClient::GetStateString() const { MCSClient::MCSClient(const std::string& version_string, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) + GCMStore* gcm_store, + GCMStatsRecorder* recorder) : version_string_(version_string), clock_(clock), state_(UNINITIALIZED), @@ -160,6 +170,7 @@ MCSClient::MCSClient(const std::string& version_string, stream_id_out_(0), stream_id_in_(0), gcm_store_(gcm_store), + recorder_(recorder), weak_ptr_factory_(this) { } @@ -495,6 +506,11 @@ void MCSClient::SendPacketToWire(ReliablePacketInfo* packet_info) { base::Time::kMicrosecondsPerSecond) - sent; DVLOG(1) << "Message was queued for " << queued << " seconds."; data_message->set_queued(queued); + recorder_->RecordDataSentToWire( + data_message->category(), + data_message->to(), + data_message->id(), + queued); } // Set the proper last received stream id to acknowledge received server @@ -862,6 +878,13 @@ void MCSClient::NotifyMessageSendStatus( const mcs_proto::DataMessageStanza* data_message_stanza = reinterpret_cast<const mcs_proto::DataMessageStanza*>(&protobuf); + recorder_->RecordNotifySendStatus( + data_message_stanza->category(), + data_message_stanza->to(), + data_message_stanza->id(), + status, + protobuf.ByteSize(), + data_message_stanza->ttl()); message_sent_callback_.Run( data_message_stanza->device_user_id(), data_message_stanza->category(), diff --git a/google_apis/gcm/engine/mcs_client.h b/google_apis/gcm/engine/mcs_client.h index 1943be6..cc915e4 100644 --- a/google_apis/gcm/engine/mcs_client.h +++ b/google_apis/gcm/engine/mcs_client.h @@ -37,6 +37,7 @@ namespace gcm { class CollapseKey; class ConnectionFactory; +class GCMStatsRecorder; struct ReliablePacketInfo; // An MCS client. This client is in charge of all communications with an @@ -54,6 +55,8 @@ class GCM_EXPORT MCSClient { CONNECTED, // Connected and running. }; + // Any change made to this enum should have corresponding change in the + // GetMessageSendStatusString(...) function in mcs_client.cc. enum MessageSendStatus { // Message was queued succcessfully. QUEUED, @@ -61,14 +64,19 @@ class GCM_EXPORT MCSClient { SENT, // Message not saved, because total queue size limit reached. QUEUE_SIZE_LIMIT_REACHED, - // Messgae not saved, because app queue size limit reached. + // Message not saved, because app queue size limit reached. APP_QUEUE_SIZE_LIMIT_REACHED, // Message too large to send. MESSAGE_TOO_LARGE, // Message not send becuase of TTL = 0 and no working connection. NO_CONNECTION_ON_ZERO_TTL, // Message exceeded TTL. - TTL_EXCEEDED + TTL_EXCEEDED, + + // NOTE: always keep this entry at the end. Add new status types only + // immediately above this line. Make sure to update the corresponding + // histogram enum accordingly. + SEND_STATUS_COUNT }; // Callback for MCSClient's error conditions. @@ -89,7 +97,8 @@ class GCM_EXPORT MCSClient { MCSClient(const std::string& version_string, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store); + GCMStore* gcm_store, + GCMStatsRecorder* recorder); virtual ~MCSClient(); // Initialize the client. Will load any previous id/token information as well @@ -127,6 +136,12 @@ class GCM_EXPORT MCSClient { // Returns the current state of the client. State state() const { return state_; } + // Returns the size of the send message queue. + int GetSendQueueSize() const; + + // Returns the size of the resend messaage queue. + int GetResendQueueSize() const; + // Returns text representation of the state enum. std::string GetStateString() const; @@ -259,6 +274,9 @@ class GCM_EXPORT MCSClient { // Manager to handle triggering/detecting heartbeats. HeartbeatManager heartbeat_manager_; + // Recorder that records GCM activities for debugging purpose. Not owned. + GCMStatsRecorder* recorder_; + base::WeakPtrFactory<MCSClient> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(MCSClient); diff --git a/google_apis/gcm/engine/mcs_client_unittest.cc b/google_apis/gcm/engine/mcs_client_unittest.cc index b3e2f0d..a062136 100644 --- a/google_apis/gcm/engine/mcs_client_unittest.cc +++ b/google_apis/gcm/engine/mcs_client_unittest.cc @@ -15,6 +15,7 @@ #include "google_apis/gcm/engine/fake_connection_factory.h" #include "google_apis/gcm/engine/fake_connection_handler.h" #include "google_apis/gcm/engine/gcm_store_impl.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "testing/gtest/include/gtest/gtest.h" namespace gcm { @@ -67,8 +68,9 @@ class TestMCSClient : public MCSClient { public: TestMCSClient(base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) - : MCSClient("", clock, connection_factory, gcm_store), + GCMStore* gcm_store, + gcm::GCMStatsRecorder* recorder) + : MCSClient("", clock, connection_factory, gcm_store, recorder), next_id_(0) { } @@ -136,6 +138,8 @@ class MCSClientTest : public testing::Test { scoped_ptr<MCSMessage> received_message_; std::string sent_message_id_; MCSClient::MessageSendStatus message_send_status_; + + gcm::GCMStatsRecorder recorder_; }; MCSClientTest::MCSClientTest() @@ -166,7 +170,8 @@ void MCSClientTest::BuildMCSClient() { message_loop_.message_loop_proxy())); mcs_client_.reset(new TestMCSClient(&clock_, &connection_factory_, - gcm_store_.get())); + gcm_store_.get(), + &recorder_)); } void MCSClientTest::InitializeClient() { diff --git a/google_apis/gcm/gcm.gyp b/google_apis/gcm/gcm.gyp index 9843776..8f99174 100644 --- a/google_apis/gcm/gcm.gyp +++ b/google_apis/gcm/gcm.gyp @@ -72,6 +72,8 @@ 'gcm_client.h', 'gcm_client_impl.cc', 'gcm_client_impl.h', + 'monitoring/gcm_stats_recorder.cc', + 'monitoring/gcm_stats_recorder.h', 'protocol/android_checkin.proto', 'protocol/checkin.proto', 'protocol/mcs.proto', @@ -138,7 +140,8 @@ 'engine/mcs_client_unittest.cc', 'engine/registration_request_unittest.cc', 'engine/unregistration_request_unittest.cc', - 'gcm_client_impl_unittest.cc' + 'gcm_client_impl_unittest.cc', + 'monitoring/gcm_stats_recorder_unittest.cc' ] }, ], diff --git a/google_apis/gcm/gcm_client.cc b/google_apis/gcm/gcm_client.cc index 3bdd699..75884d6 100644 --- a/google_apis/gcm/gcm_client.cc +++ b/google_apis/gcm/gcm_client.cc @@ -24,7 +24,12 @@ GCMClient::SendErrorDetails::SendErrorDetails() : result(UNKNOWN_ERROR) {} GCMClient::SendErrorDetails::~SendErrorDetails() {} GCMClient::GCMStatistics::GCMStatistics() - : gcm_client_created(false), connection_client_created(false) { + : is_recording(false), + gcm_client_created(false), + connection_client_created(false), + android_id(0), + send_queue_size(0), + resend_queue_size(0) { } GCMClient::GCMStatistics::~GCMStatistics() { diff --git a/google_apis/gcm/gcm_client.h b/google_apis/gcm/gcm_client.h index 16ba53b..5996c06 100644 --- a/google_apis/gcm/gcm_client.h +++ b/google_apis/gcm/gcm_client.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "google_apis/gcm/base/gcm_export.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" template <class T> class scoped_refptr; @@ -94,11 +95,17 @@ class GCM_EXPORT GCMClient { GCMStatistics(); ~GCMStatistics(); + bool is_recording; bool gcm_client_created; std::string gcm_client_state; bool connection_client_created; std::string connection_state; uint64 android_id; + std::vector<std::string> registered_app_ids; + int send_queue_size; + int resend_queue_size; + + std::vector<GCMStatsRecorder::SendingActivity> sending_activities; }; // A delegate interface that allows the GCMClient instance to interact with @@ -208,6 +215,12 @@ class GCM_EXPORT GCMClient { const std::string& receiver_id, const OutgoingMessage& message) = 0; + // Enables or disables internal activity recording. + virtual void SetRecording(bool recording) = 0; + + // Clear all recorded GCM activity logs. + virtual void ClearActivityLogs() = 0; + // Gets internal states and statistics. virtual GCMStatistics GetStatistics() const = 0; }; diff --git a/google_apis/gcm/gcm_client_impl.cc b/google_apis/gcm/gcm_client_impl.cc index 80c58d8..e152d63 100644 --- a/google_apis/gcm/gcm_client_impl.cc +++ b/google_apis/gcm/gcm_client_impl.cc @@ -12,6 +12,7 @@ #include "base/metrics/histogram.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/time/default_clock.h" #include "google_apis/gcm/base/mcs_message.h" #include "google_apis/gcm/base/mcs_util.h" @@ -19,6 +20,7 @@ #include "google_apis/gcm/engine/connection_factory_impl.h" #include "google_apis/gcm/engine/gcm_store_impl.h" #include "google_apis/gcm/engine/mcs_client.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "google_apis/gcm/protocol/mcs.pb.h" #include "net/http/http_network_session.h" #include "net/url_request/url_request_context.h" @@ -130,12 +132,14 @@ scoped_ptr<MCSClient> GCMInternalsBuilder::BuildMCSClient( const std::string& version, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) { + GCMStore* gcm_store, + GCMStatsRecorder* recorder) { return make_scoped_ptr<MCSClient>( new MCSClient(version, clock, connection_factory, - gcm_store)); + gcm_store, + recorder)); } scoped_ptr<ConnectionFactory> GCMInternalsBuilder::BuildConnectionFactory( @@ -241,7 +245,8 @@ void GCMClientImpl::InitializeMCSClient( chrome_build_proto_.chrome_version(), clock_.get(), connection_factory_.get(), - gcm_store_.get()).Pass(); + gcm_store_.get(), + &recorder_).Pass(); mcs_client_->Initialize( base::Bind(&GCMClientImpl::OnMCSError, weak_ptr_factory_.GetWeakPtr()), @@ -557,16 +562,33 @@ std::string GCMClientImpl::GetStateString() const { } } +void GCMClientImpl::SetRecording(bool recording) { + recorder_.SetRecording(recording); +} + +void GCMClientImpl::ClearActivityLogs() { + recorder_.Clear(); +} + GCMClient::GCMStatistics GCMClientImpl::GetStatistics() const { GCMClient::GCMStatistics stats; - stats.gcm_client_state = GCMClientImpl::GetStateString(); + stats.gcm_client_created = true; + stats.is_recording = recorder_.is_recording(); + stats.gcm_client_state = GetStateString(); stats.connection_client_created = mcs_client_.get() != NULL; if (mcs_client_.get()) { stats.connection_state = mcs_client_->GetStateString(); - // TODO(juyik): add more statistics such as message metadata list, etc. + stats.send_queue_size = mcs_client_->GetSendQueueSize(); + stats.resend_queue_size = mcs_client_->GetResendQueueSize(); } if (device_checkin_info_.android_id > 0) stats.android_id = device_checkin_info_.android_id; + recorder_.CollectSendingActivities(&stats.sending_activities); + + for (RegistrationInfoMap::const_iterator it = registrations_.begin(); + it != registrations_.end(); ++it) { + stats.registered_app_ids.push_back(it->first); + } return stats; } @@ -695,6 +717,10 @@ void GCMClientImpl::HandleIncomingSendError( send_error_details.additional_data.erase(iter); } + recorder_.RecordIncomingSendError( + data_message_stanza.category(), + data_message_stanza.to(), + data_message_stanza.id()); delegate_->OnMessageSendError(data_message_stanza.category(), send_error_details); } diff --git a/google_apis/gcm/gcm_client_impl.h b/google_apis/gcm/gcm_client_impl.h index 7458c70..c4e6068 100644 --- a/google_apis/gcm/gcm_client_impl.h +++ b/google_apis/gcm/gcm_client_impl.h @@ -19,6 +19,8 @@ #include "google_apis/gcm/engine/registration_request.h" #include "google_apis/gcm/engine/unregistration_request.h" #include "google_apis/gcm/gcm_client.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" +#include "google_apis/gcm/protocol/android_checkin.pb.h" #include "google_apis/gcm/protocol/checkin.pb.h" #include "net/base/net_log.h" #include "net/url_request/url_request_context_getter.h" @@ -29,6 +31,10 @@ namespace base { class Clock; } // namespace base +namespace mcs_proto { +class DataMessageStanza; +} // namespace mcs_proto + namespace net { class HttpNetworkSession; } // namespace net @@ -51,7 +57,8 @@ class GCM_EXPORT GCMInternalsBuilder { const std::string& version, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store); + GCMStore* gcm_store, + GCMStatsRecorder* recorder); virtual scoped_ptr<ConnectionFactory> BuildConnectionFactory( const std::vector<GURL>& endpoints, const net::BackoffEntry::Policy& backoff_policy, @@ -86,6 +93,8 @@ class GCM_EXPORT GCMClientImpl : public GCMClient { virtual void Send(const std::string& app_id, const std::string& receiver_id, const OutgoingMessage& message) OVERRIDE; + virtual void SetRecording(bool recording) OVERRIDE; + virtual void ClearActivityLogs() OVERRIDE; virtual GCMStatistics GetStatistics() const OVERRIDE; private: @@ -210,6 +219,9 @@ class GCM_EXPORT GCMClientImpl : public GCMClient { // Builder for the GCM internals (mcs client, etc.). scoped_ptr<GCMInternalsBuilder> internals_builder_; + // Recorder that logs GCM activities. + GCMStatsRecorder recorder_; + // State of the GCM Client Implementation. State state_; diff --git a/google_apis/gcm/gcm_client_impl_unittest.cc b/google_apis/gcm/gcm_client_impl_unittest.cc index 709418c..7f6a937 100644 --- a/google_apis/gcm/gcm_client_impl_unittest.cc +++ b/google_apis/gcm/gcm_client_impl_unittest.cc @@ -14,6 +14,7 @@ #include "google_apis/gcm/base/mcs_util.h" #include "google_apis/gcm/engine/fake_connection_factory.h" #include "google_apis/gcm/engine/fake_connection_handler.h" +#include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "google_apis/gcm/protocol/android_checkin.pb.h" #include "google_apis/gcm/protocol/checkin.pb.h" #include "google_apis/gcm/protocol/mcs.pb.h" @@ -67,7 +68,8 @@ class FakeMCSClient : public MCSClient { public: FakeMCSClient(base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store); + GCMStore* gcm_store, + GCMStatsRecorder* recorder); virtual ~FakeMCSClient(); virtual void Login(uint64 android_id, uint64 security_token) OVERRIDE; virtual void SendMessage(const MCSMessage& message) OVERRIDE; @@ -88,8 +90,9 @@ class FakeMCSClient : public MCSClient { FakeMCSClient::FakeMCSClient(base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) - : MCSClient("", clock, connection_factory, gcm_store), + GCMStore* gcm_store, + GCMStatsRecorder* recorder) + : MCSClient("", clock, connection_factory, gcm_store, recorder), last_android_id_(0u), last_security_token_(0u), last_message_tag_(kNumProtoTypes) { @@ -122,7 +125,8 @@ class FakeGCMInternalsBuilder : public GCMInternalsBuilder { const std::string& version, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) OVERRIDE; + GCMStore* gcm_store, + GCMStatsRecorder* recorder) OVERRIDE; virtual scoped_ptr<ConnectionFactory> BuildConnectionFactory( const std::vector<GURL>& endpoints, const net::BackoffEntry::Policy& backoff_policy, @@ -142,10 +146,12 @@ scoped_ptr<MCSClient> FakeGCMInternalsBuilder::BuildMCSClient( const std::string& version, base::Clock* clock, ConnectionFactory* connection_factory, - GCMStore* gcm_store) { + GCMStore* gcm_store, + GCMStatsRecorder* recorder) { return make_scoped_ptr<MCSClient>(new FakeMCSClient(clock, connection_factory, - gcm_store)); + gcm_store, + recorder)); } scoped_ptr<ConnectionFactory> FakeGCMInternalsBuilder::BuildConnectionFactory( diff --git a/google_apis/gcm/monitoring/gcm_stats_recorder.cc b/google_apis/gcm/monitoring/gcm_stats_recorder.cc new file mode 100644 index 0000000..6e0cb48 --- /dev/null +++ b/google_apis/gcm/monitoring/gcm_stats_recorder.cc @@ -0,0 +1,150 @@ +// 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 "google_apis/gcm/monitoring/gcm_stats_recorder.h" + +#include <deque> +#include <vector> + +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" + +namespace gcm { + +const uint32 MAX_LOGGED_ACTIVITY_COUNT = 100; + +namespace { + +// Insert an itme to the front of deque while maintaining the size of the deque. +// Overflow item is discarded. +template <typename T> +T* InsertCircularBuffer(std::deque<T>* q, const T& item) { + DCHECK(q); + q->push_front(item); + if (q->size() > MAX_LOGGED_ACTIVITY_COUNT) { + q->pop_back(); + } + return &q->front(); +} + +// Helper for getting string representation of the MessageSendStatus enum. +std::string GetMessageSendStatusString( + gcm::MCSClient::MessageSendStatus status) { + switch (status) { + case gcm::MCSClient::QUEUED: + return "QUEUED"; + case gcm::MCSClient::SENT: + return "SENT"; + case gcm::MCSClient::QUEUE_SIZE_LIMIT_REACHED: + return "QUEUE_SIZE_LIMIT_REACHED"; + case gcm::MCSClient::APP_QUEUE_SIZE_LIMIT_REACHED: + return "APP_QUEUE_SIZE_LIMIT_REACHED"; + case gcm::MCSClient::MESSAGE_TOO_LARGE: + return "MESSAGE_TOO_LARGE"; + case gcm::MCSClient::NO_CONNECTION_ON_ZERO_TTL: + return "NO_CONNECTION_ON_ZERO_TTL"; + case gcm::MCSClient::TTL_EXCEEDED: + return "TTL_EXCEEDED"; + default: + NOTREACHED(); + return "UNKNOWN"; + } +} + +} // namespace + +GCMStatsRecorder::Activity::Activity() + : time(base::Time::Now()) { +} + +GCMStatsRecorder::Activity::~Activity() { +} + +GCMStatsRecorder::SendingActivity::SendingActivity() { +} + +GCMStatsRecorder::SendingActivity::~SendingActivity() { +} + +GCMStatsRecorder::GCMStatsRecorder() : is_recording_(false) { +} + +GCMStatsRecorder::~GCMStatsRecorder() { +} + +void GCMStatsRecorder::SetRecording(bool recording) { + is_recording_ = recording; +} + +void GCMStatsRecorder::Clear() { + sending_activities_.clear(); +} + +void GCMStatsRecorder::CollectSendingActivities( + std::vector<SendingActivity>* activities) const { + activities->insert(activities->begin(), + sending_activities_.begin(), + sending_activities_.end()); +} + +void GCMStatsRecorder::RecordSending(const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + const std::string& event, + const std::string& details) { + SendingActivity data; + SendingActivity* inserted_data = InsertCircularBuffer( + &sending_activities_, data); + inserted_data->app_id = app_id; + inserted_data->receiver_id = receiver_id; + inserted_data->message_id = message_id; + inserted_data->event = event; + inserted_data->details = details; +} + +void GCMStatsRecorder::RecordDataSentToWire( + const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + int queued) { + if (is_recording_) { + RecordSending(app_id, receiver_id, message_id, "Data msg sent to wire", + base::StringPrintf("Msg queued for %d seconds", queued)); + } +} + +void GCMStatsRecorder::RecordNotifySendStatus( + const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + gcm::MCSClient::MessageSendStatus status, + int byte_size, + int ttl) { + UMA_HISTOGRAM_ENUMERATION("GCM.SendMessageStatus", status, + gcm::MCSClient::SEND_STATUS_COUNT); + if (is_recording_) { + RecordSending( + app_id, + receiver_id, + message_id, + base::StringPrintf("SEND status: %s", + GetMessageSendStatusString(status).c_str()), + base::StringPrintf("Msg size: %d bytes, TTL: %d", byte_size, ttl)); + } +} + +void GCMStatsRecorder::RecordIncomingSendError( + const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id) { + UMA_HISTOGRAM_COUNTS("GCM.IncomingSendErrors", 1); + if (is_recording_) { + RecordSending(app_id, receiver_id, message_id, "Received 'send error' msg", + std::string()); + } +} + +} // namespace gcm diff --git a/google_apis/gcm/monitoring/gcm_stats_recorder.h b/google_apis/gcm/monitoring/gcm_stats_recorder.h new file mode 100644 index 0000000..71b6c6a --- /dev/null +++ b/google_apis/gcm/monitoring/gcm_stats_recorder.h @@ -0,0 +1,101 @@ +// 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 GOOGLE_APIS_GCM_GCM_STATS_RECORDER_H_ +#define GOOGLE_APIS_GCM_GCM_STATS_RECORDER_H_ + +#include <deque> +#include <string> +#include <vector> + +#include "base/time/time.h" +#include "google_apis/gcm/base/gcm_export.h" +#include "google_apis/gcm/engine/mcs_client.h" + +namespace gcm { + +// Records GCM internal stats and activities for debugging purpose. Recording +// can be turned on/off by calling SetRecording(...) function. It is turned off +// by default. +// This class is not thread safe. It is meant to be owned by a gcm client +// instance. +class GCM_EXPORT GCMStatsRecorder { + public: + // Contains data that are common to all activity kinds below. + struct GCM_EXPORT Activity { + Activity(); + virtual ~Activity(); + + base::Time time; + std::string event; // A short description of the event. + std::string details; // Any additional detail about the event. + }; + + // Contains relevant data of a send-message step. + struct GCM_EXPORT SendingActivity : Activity { + SendingActivity(); + virtual ~SendingActivity(); + + std::string app_id; + std::string receiver_id; + std::string message_id; + }; + + GCMStatsRecorder(); + virtual ~GCMStatsRecorder(); + + // Indicates whether the recorder is currently recording activities or not. + bool is_recording() const { + return is_recording_; + } + + // Turns recording on/off. + void SetRecording(bool recording); + + // Clear all recorded activities. + void Clear(); + + // Records that an outgoing data message was sent over the wire. + void RecordDataSentToWire(const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + int queued); + // Records that the MCS client sent a 'send status' notification to callback. + void RecordNotifySendStatus(const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + MCSClient::MessageSendStatus status, + int byte_size, + int ttl); + // Records that a 'send error' message was received. + void RecordIncomingSendError(const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id); + + // Records that a sending activity has occurred. It will be inserted to the + // front of a queue ao that entries in the queue had reverse chronological + // order. + void CollectSendingActivities(std::vector<SendingActivity>* activities) const; + + const std::deque<SendingActivity>& sending_activities() const { + return sending_activities_; + } + + protected: + void RecordSending(const std::string& app_id, + const std::string& receiver_id, + const std::string& message_id, + const std::string& event, + const std::string& details); + + bool is_recording_; + + std::deque<SendingActivity> sending_activities_; + + DISALLOW_COPY_AND_ASSIGN(GCMStatsRecorder); +}; + +} // namespace gcm + +#endif // GOOGLE_APIS_GCM_GCM_STATS_RECORDER_H_ diff --git a/google_apis/gcm/monitoring/gcm_stats_recorder_unittest.cc b/google_apis/gcm/monitoring/gcm_stats_recorder_unittest.cc new file mode 100644 index 0000000..488b31b --- /dev/null +++ b/google_apis/gcm/monitoring/gcm_stats_recorder_unittest.cc @@ -0,0 +1,136 @@ +// 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 "google_apis/gcm/monitoring/gcm_stats_recorder.h" + +#include <deque> +#include <string> + +#include "google_apis/gcm/engine/mcs_client.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gcm { + +namespace { + +static const char kAppId[] = "app id 1"; +static const char kReceiverId[] = "receiver 1"; +static const char kMessageId[] = "message id 1"; +static const int kQueuedSec = 5; +static const gcm::MCSClient::MessageSendStatus kMessageSendStatus = + gcm::MCSClient::QUEUED; +static const int kByteSize = 99; +static const int kTTL = 7; + +static const char kDataSentToWireEvent[] = "Data msg sent to wire"; +static const char kSentToWireDetails[] = "Msg queued for 5 seconds"; +static const char kNotifySendStatusEvent[] = "SEND status: QUEUED"; +static const char kNotifySendStatusDetails[] = "Msg size: 99 bytes, TTL: 7"; +static const char kIncomingSendErrorEvent[] = "Received 'send error' msg"; +static const char kIncomingSendErrorDetails[] = ""; + +} // namespace + +class GCMStatsRecorderTest : public testing::Test { + public: + GCMStatsRecorderTest(); + virtual ~GCMStatsRecorderTest(); + virtual void SetUp() OVERRIDE; + + void VerifyRecordedSendingCount(int expected_count) { + EXPECT_EQ(expected_count, + static_cast<int>(recorder_.sending_activities().size())); + } + + void VerifyDataSentToWire(const std::string& remark){ + VerifyData(recorder_.sending_activities(), + kDataSentToWireEvent, + kSentToWireDetails, + remark); + } + + void VerifyNotifySendStatus(const std::string& remark){ + VerifyData(recorder_.sending_activities(), + kNotifySendStatusEvent, + kNotifySendStatusDetails, + remark); + } + + void VerifyIncomingSendError(const std::string& remark){ + VerifyData(recorder_.sending_activities(), + kIncomingSendErrorEvent, + kIncomingSendErrorDetails, + remark); + } + + protected: + template <typename T> + void VerifyData(const std::deque<T>& queue, const std::string& event, + const std::string& details, const std::string& remark) { + EXPECT_EQ(kAppId, queue.front().app_id) << remark; + EXPECT_EQ(kReceiverId, queue.front().receiver_id) << remark; + EXPECT_EQ(kMessageId, queue.front().message_id) << remark; + EXPECT_EQ(event, queue.front().event) << remark; + EXPECT_EQ(details, queue.front().details) << remark; + } + + GCMStatsRecorder recorder_; +}; + +GCMStatsRecorderTest::GCMStatsRecorderTest(){ +} + +GCMStatsRecorderTest::~GCMStatsRecorderTest() {} + +void GCMStatsRecorderTest::SetUp(){ + recorder_.SetRecording(true); +} + +TEST_F(GCMStatsRecorderTest, StartStopRecordingTest) { + EXPECT_TRUE(recorder_.is_recording()); + recorder_.RecordDataSentToWire(kAppId, kReceiverId, kMessageId, kQueuedSec); + VerifyRecordedSendingCount(1); + VerifyDataSentToWire("1st call"); + + recorder_.SetRecording(false); + EXPECT_FALSE(recorder_.is_recording()); + recorder_.RecordDataSentToWire(kAppId, kReceiverId, kMessageId, kQueuedSec); + VerifyRecordedSendingCount(1); + VerifyDataSentToWire("2nd call"); +} + +TEST_F(GCMStatsRecorderTest, ClearLogTest) { + recorder_.RecordDataSentToWire(kAppId, kReceiverId, kMessageId, kQueuedSec); + VerifyRecordedSendingCount(1); + VerifyDataSentToWire("1st call"); + + recorder_.RecordNotifySendStatus(kAppId, kReceiverId, kMessageId, + kMessageSendStatus, kByteSize, kTTL); + VerifyRecordedSendingCount(2); + VerifyNotifySendStatus("2nd call"); + + recorder_.Clear(); + VerifyRecordedSendingCount(0); +} + +TEST_F(GCMStatsRecorderTest, RecordSendingTest) { + recorder_.RecordDataSentToWire(kAppId, kReceiverId, kMessageId, kQueuedSec); + VerifyRecordedSendingCount(1); + VerifyDataSentToWire("1st call"); + + recorder_.RecordNotifySendStatus(kAppId, kReceiverId, kMessageId, + kMessageSendStatus, kByteSize, kTTL); + VerifyRecordedSendingCount(2); + VerifyNotifySendStatus("2nd call"); + + recorder_.RecordIncomingSendError(kAppId, kReceiverId, kMessageId); + VerifyRecordedSendingCount(3); + VerifyIncomingSendError("3rd call"); + + recorder_.RecordDataSentToWire(kAppId, kReceiverId, kMessageId, kQueuedSec); + VerifyRecordedSendingCount(4); + VerifyDataSentToWire("4th call"); +} + +} // namespace gcm |