gcm_stats_recorder_impl.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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. 4 5#include "components/gcm_driver/gcm_stats_recorder_impl.h" 6 7#include <deque> 8#include <vector> 9 10#include "base/format_macros.h" 11#include "base/logging.h" 12#include "base/metrics/histogram.h" 13#include "base/strings/string_util.h" 14#include "base/strings/stringprintf.h" 15 16namespace gcm { 17 18const uint32 MAX_LOGGED_ACTIVITY_COUNT = 100; 19 20namespace { 21 22// Insert an item to the front of deque while maintaining the size of the deque. 23// Overflow item is discarded. 24template <typename T> 25T* InsertCircularBuffer(std::deque<T>* q, const T& item) { 26 DCHECK(q); 27 q->push_front(item); 28 if (q->size() > MAX_LOGGED_ACTIVITY_COUNT) { 29 q->pop_back(); 30 } 31 return &q->front(); 32} 33 34// Helper for getting string representation of the MessageSendStatus enum. 35std::string GetMessageSendStatusString( 36 gcm::MCSClient::MessageSendStatus status) { 37 switch (status) { 38 case gcm::MCSClient::QUEUED: 39 return "QUEUED"; 40 case gcm::MCSClient::SENT: 41 return "SENT"; 42 case gcm::MCSClient::QUEUE_SIZE_LIMIT_REACHED: 43 return "QUEUE_SIZE_LIMIT_REACHED"; 44 case gcm::MCSClient::APP_QUEUE_SIZE_LIMIT_REACHED: 45 return "APP_QUEUE_SIZE_LIMIT_REACHED"; 46 case gcm::MCSClient::MESSAGE_TOO_LARGE: 47 return "MESSAGE_TOO_LARGE"; 48 case gcm::MCSClient::NO_CONNECTION_ON_ZERO_TTL: 49 return "NO_CONNECTION_ON_ZERO_TTL"; 50 case gcm::MCSClient::TTL_EXCEEDED: 51 return "TTL_EXCEEDED"; 52 default: 53 NOTREACHED(); 54 return "UNKNOWN"; 55 } 56} 57 58// Helper for getting string representation of the 59// ConnectionFactory::ConnectionResetReason enum. 60std::string GetConnectionResetReasonString( 61 gcm::ConnectionFactory::ConnectionResetReason reason) { 62 switch (reason) { 63 case gcm::ConnectionFactory::LOGIN_FAILURE: 64 return "LOGIN_FAILURE"; 65 case gcm::ConnectionFactory::CLOSE_COMMAND: 66 return "CLOSE_COMMAND"; 67 case gcm::ConnectionFactory::HEARTBEAT_FAILURE: 68 return "HEARTBEAT_FAILURE"; 69 case gcm::ConnectionFactory::SOCKET_FAILURE: 70 return "SOCKET_FAILURE"; 71 case gcm::ConnectionFactory::NETWORK_CHANGE: 72 return "NETWORK_CHANGE"; 73 default: 74 NOTREACHED(); 75 return "UNKNOWN_REASON"; 76 } 77} 78 79// Helper for getting string representation of the RegistrationRequest::Status 80// enum. 81std::string GetRegistrationStatusString( 82 gcm::RegistrationRequest::Status status) { 83 switch (status) { 84 case gcm::RegistrationRequest::SUCCESS: 85 return "SUCCESS"; 86 case gcm::RegistrationRequest::INVALID_PARAMETERS: 87 return "INVALID_PARAMETERS"; 88 case gcm::RegistrationRequest::INVALID_SENDER: 89 return "INVALID_SENDER"; 90 case gcm::RegistrationRequest::AUTHENTICATION_FAILED: 91 return "AUTHENTICATION_FAILED"; 92 case gcm::RegistrationRequest::DEVICE_REGISTRATION_ERROR: 93 return "DEVICE_REGISTRATION_ERROR"; 94 case gcm::RegistrationRequest::UNKNOWN_ERROR: 95 return "UNKNOWN_ERROR"; 96 case gcm::RegistrationRequest::URL_FETCHING_FAILED: 97 return "URL_FETCHING_FAILED"; 98 case gcm::RegistrationRequest::HTTP_NOT_OK: 99 return "HTTP_NOT_OK"; 100 case gcm::RegistrationRequest::RESPONSE_PARSING_FAILED: 101 return "RESPONSE_PARSING_FAILED"; 102 case gcm::RegistrationRequest::REACHED_MAX_RETRIES: 103 return "REACHED_MAX_RETRIES"; 104 default: 105 NOTREACHED(); 106 return "UNKNOWN_STATUS"; 107 } 108} 109 110// Helper for getting string representation of the RegistrationRequest::Status 111// enum. 112std::string GetUnregistrationStatusString( 113 gcm::UnregistrationRequest::Status status) { 114 switch (status) { 115 case gcm::UnregistrationRequest::SUCCESS: 116 return "SUCCESS"; 117 case gcm::UnregistrationRequest::URL_FETCHING_FAILED: 118 return "URL_FETCHING_FAILED"; 119 case gcm::UnregistrationRequest::NO_RESPONSE_BODY: 120 return "NO_RESPONSE_BODY"; 121 case gcm::UnregistrationRequest::RESPONSE_PARSING_FAILED: 122 return "RESPONSE_PARSING_FAILED"; 123 case gcm::UnregistrationRequest::INCORRECT_APP_ID: 124 return "INCORRECT_APP_ID"; 125 case gcm::UnregistrationRequest::INVALID_PARAMETERS: 126 return "INVALID_PARAMETERS"; 127 case gcm::UnregistrationRequest::SERVICE_UNAVAILABLE: 128 return "SERVICE_UNAVAILABLE"; 129 case gcm::UnregistrationRequest::INTERNAL_SERVER_ERROR: 130 return "INTERNAL_SERVER_ERROR"; 131 case gcm::UnregistrationRequest::HTTP_NOT_OK: 132 return "HTTP_NOT_OK"; 133 case gcm::UnregistrationRequest::UNKNOWN_ERROR: 134 return "UNKNOWN_ERROR"; 135 default: 136 NOTREACHED(); 137 return "UNKNOWN_STATUS"; 138 } 139} 140 141} // namespace 142 143GCMStatsRecorderImpl::GCMStatsRecorderImpl() 144 : is_recording_(false), 145 delegate_(NULL) { 146} 147 148GCMStatsRecorderImpl::~GCMStatsRecorderImpl() { 149} 150 151void GCMStatsRecorderImpl::SetRecording(bool recording) { 152 is_recording_ = recording; 153} 154 155void GCMStatsRecorderImpl::SetDelegate(Delegate* delegate) { 156 delegate_ = delegate; 157} 158 159void GCMStatsRecorderImpl::Clear() { 160 checkin_activities_.clear(); 161 connection_activities_.clear(); 162 registration_activities_.clear(); 163 receiving_activities_.clear(); 164 sending_activities_.clear(); 165} 166 167void GCMStatsRecorderImpl::NotifyActivityRecorded() { 168 if (delegate_) 169 delegate_->OnActivityRecorded(); 170} 171 172void GCMStatsRecorderImpl::RecordCheckin( 173 const std::string& event, 174 const std::string& details) { 175 CheckinActivity data; 176 CheckinActivity* inserted_data = InsertCircularBuffer( 177 &checkin_activities_, data); 178 inserted_data->event = event; 179 inserted_data->details = details; 180 NotifyActivityRecorded(); 181} 182 183void GCMStatsRecorderImpl::RecordCheckinInitiated(uint64 android_id) { 184 if (!is_recording_) 185 return; 186 RecordCheckin("Checkin initiated", 187 base::StringPrintf("Android Id: %" PRIu64, android_id)); 188} 189 190void GCMStatsRecorderImpl::RecordCheckinDelayedDueToBackoff(int64 delay_msec) { 191 if (!is_recording_) 192 return; 193 RecordCheckin("Checkin backoff", 194 base::StringPrintf("Delayed for %" PRId64 " msec", 195 delay_msec)); 196} 197 198void GCMStatsRecorderImpl::RecordCheckinSuccess() { 199 if (!is_recording_) 200 return; 201 RecordCheckin("Checkin succeeded", std::string()); 202} 203 204void GCMStatsRecorderImpl::RecordCheckinFailure(std::string status, 205 bool will_retry) { 206 if (!is_recording_) 207 return; 208 RecordCheckin("Checkin failed", base::StringPrintf( 209 "%s.%s", 210 status.c_str(), 211 will_retry ? " Will retry." : "Will not retry.")); 212} 213 214void GCMStatsRecorderImpl::RecordConnection( 215 const std::string& event, 216 const std::string& details) { 217 ConnectionActivity data; 218 ConnectionActivity* inserted_data = InsertCircularBuffer( 219 &connection_activities_, data); 220 inserted_data->event = event; 221 inserted_data->details = details; 222 NotifyActivityRecorded(); 223} 224 225void GCMStatsRecorderImpl::RecordConnectionInitiated(const std::string& host) { 226 if (!is_recording_) 227 return; 228 RecordConnection("Connection initiated", host); 229} 230 231void GCMStatsRecorderImpl::RecordConnectionDelayedDueToBackoff( 232 int64 delay_msec) { 233 if (!is_recording_) 234 return; 235 RecordConnection("Connection backoff", 236 base::StringPrintf("Delayed for %" PRId64 " msec", 237 delay_msec)); 238} 239 240void GCMStatsRecorderImpl::RecordConnectionSuccess() { 241 if (!is_recording_) 242 return; 243 RecordConnection("Connection succeeded", std::string()); 244} 245 246void GCMStatsRecorderImpl::RecordConnectionFailure(int network_error) { 247 if (!is_recording_) 248 return; 249 RecordConnection("Connection failed", 250 base::StringPrintf("With network error %d", network_error)); 251} 252 253void GCMStatsRecorderImpl::RecordConnectionResetSignaled( 254 ConnectionFactory::ConnectionResetReason reason) { 255 if (!is_recording_) 256 return; 257 RecordConnection("Connection reset", 258 GetConnectionResetReasonString(reason)); 259} 260 261void GCMStatsRecorderImpl::RecordRegistration( 262 const std::string& app_id, 263 const std::string& sender_ids, 264 const std::string& event, 265 const std::string& details) { 266 RegistrationActivity data; 267 RegistrationActivity* inserted_data = InsertCircularBuffer( 268 ®istration_activities_, data); 269 inserted_data->app_id = app_id; 270 inserted_data->sender_ids = sender_ids; 271 inserted_data->event = event; 272 inserted_data->details = details; 273 NotifyActivityRecorded(); 274} 275 276void GCMStatsRecorderImpl::RecordRegistrationSent( 277 const std::string& app_id, 278 const std::string& sender_ids) { 279 UMA_HISTOGRAM_COUNTS("GCM.RegistrationRequest", 1); 280 if (!is_recording_) 281 return; 282 RecordRegistration(app_id, sender_ids, 283 "Registration request sent", std::string()); 284} 285 286void GCMStatsRecorderImpl::RecordRegistrationResponse( 287 const std::string& app_id, 288 const std::vector<std::string>& sender_ids, 289 RegistrationRequest::Status status) { 290 if (!is_recording_) 291 return; 292 RecordRegistration(app_id, JoinString(sender_ids, ","), 293 "Registration response received", 294 GetRegistrationStatusString(status)); 295} 296 297void GCMStatsRecorderImpl::RecordRegistrationRetryRequested( 298 const std::string& app_id, 299 const std::vector<std::string>& sender_ids, 300 int retries_left) { 301 if (!is_recording_) 302 return; 303 RecordRegistration(app_id, JoinString(sender_ids, ","), 304 "Registration retry requested", 305 base::StringPrintf("Retries left: %d", retries_left)); 306} 307 308void GCMStatsRecorderImpl::RecordUnregistrationSent( 309 const std::string& app_id) { 310 UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRequest", 1); 311 if (!is_recording_) 312 return; 313 RecordRegistration(app_id, std::string(), "Unregistration request sent", 314 std::string()); 315} 316 317void GCMStatsRecorderImpl::RecordUnregistrationResponse( 318 const std::string& app_id, 319 UnregistrationRequest::Status status) { 320 if (!is_recording_) 321 return; 322 RecordRegistration(app_id, 323 std::string(), 324 "Unregistration response received", 325 GetUnregistrationStatusString(status)); 326} 327 328void GCMStatsRecorderImpl::RecordUnregistrationRetryDelayed( 329 const std::string& app_id, 330 int64 delay_msec) { 331 if (!is_recording_) 332 return; 333 RecordRegistration(app_id, 334 std::string(), 335 "Unregistration retry delayed", 336 base::StringPrintf("Delayed for %" PRId64 " msec", 337 delay_msec)); 338} 339 340void GCMStatsRecorderImpl::RecordReceiving( 341 const std::string& app_id, 342 const std::string& from, 343 int message_byte_size, 344 const std::string& event, 345 const std::string& details) { 346 ReceivingActivity data; 347 ReceivingActivity* inserted_data = InsertCircularBuffer( 348 &receiving_activities_, data); 349 inserted_data->app_id = app_id; 350 inserted_data->from = from; 351 inserted_data->message_byte_size = message_byte_size; 352 inserted_data->event = event; 353 inserted_data->details = details; 354 NotifyActivityRecorded(); 355} 356 357void GCMStatsRecorderImpl::RecordDataMessageReceived( 358 const std::string& app_id, 359 const std::string& from, 360 int message_byte_size, 361 bool to_registered_app, 362 ReceivedMessageType message_type) { 363 if (to_registered_app) 364 UMA_HISTOGRAM_COUNTS("GCM.DataMessageReceived", 1); 365 if (!is_recording_) 366 return; 367 if (!to_registered_app) { 368 RecordReceiving(app_id, from, message_byte_size, "Data msg received", 369 to_registered_app ? std::string() : 370 "No such registered app found"); 371 } else { 372 switch(message_type) { 373 case GCMStatsRecorderImpl::DATA_MESSAGE: 374 RecordReceiving(app_id, from, message_byte_size, "Data msg received", 375 std::string()); 376 break; 377 case GCMStatsRecorderImpl::DELETED_MESSAGES: 378 RecordReceiving(app_id, from, message_byte_size, "Data msg received", 379 "Message has been deleted on server"); 380 break; 381 default: 382 NOTREACHED(); 383 } 384 } 385} 386 387void GCMStatsRecorderImpl::CollectActivities( 388 RecordedActivities* recorder_activities) const { 389 recorder_activities->checkin_activities.insert( 390 recorder_activities->checkin_activities.begin(), 391 checkin_activities_.begin(), 392 checkin_activities_.end()); 393 recorder_activities->connection_activities.insert( 394 recorder_activities->connection_activities.begin(), 395 connection_activities_.begin(), 396 connection_activities_.end()); 397 recorder_activities->registration_activities.insert( 398 recorder_activities->registration_activities.begin(), 399 registration_activities_.begin(), 400 registration_activities_.end()); 401 recorder_activities->receiving_activities.insert( 402 recorder_activities->receiving_activities.begin(), 403 receiving_activities_.begin(), 404 receiving_activities_.end()); 405 recorder_activities->sending_activities.insert( 406 recorder_activities->sending_activities.begin(), 407 sending_activities_.begin(), 408 sending_activities_.end()); 409} 410 411void GCMStatsRecorderImpl::RecordSending(const std::string& app_id, 412 const std::string& receiver_id, 413 const std::string& message_id, 414 const std::string& event, 415 const std::string& details) { 416 SendingActivity data; 417 SendingActivity* inserted_data = InsertCircularBuffer( 418 &sending_activities_, data); 419 inserted_data->app_id = app_id; 420 inserted_data->receiver_id = receiver_id; 421 inserted_data->message_id = message_id; 422 inserted_data->event = event; 423 inserted_data->details = details; 424 NotifyActivityRecorded(); 425} 426 427void GCMStatsRecorderImpl::RecordDataSentToWire( 428 const std::string& app_id, 429 const std::string& receiver_id, 430 const std::string& message_id, 431 int queued) { 432 if (!is_recording_) 433 return; 434 RecordSending(app_id, receiver_id, message_id, "Data msg sent to wire", 435 base::StringPrintf("Msg queued for %d seconds", queued)); 436} 437 438void GCMStatsRecorderImpl::RecordNotifySendStatus( 439 const std::string& app_id, 440 const std::string& receiver_id, 441 const std::string& message_id, 442 gcm::MCSClient::MessageSendStatus status, 443 int byte_size, 444 int ttl) { 445 UMA_HISTOGRAM_ENUMERATION("GCM.SendMessageStatus", status, 446 gcm::MCSClient::SEND_STATUS_COUNT); 447 if (!is_recording_) 448 return; 449 RecordSending( 450 app_id, 451 receiver_id, 452 message_id, 453 base::StringPrintf("SEND status: %s", 454 GetMessageSendStatusString(status).c_str()), 455 base::StringPrintf("Msg size: %d bytes, TTL: %d", byte_size, ttl)); 456} 457 458void GCMStatsRecorderImpl::RecordIncomingSendError( 459 const std::string& app_id, 460 const std::string& receiver_id, 461 const std::string& message_id) { 462 UMA_HISTOGRAM_COUNTS("GCM.IncomingSendErrors", 1); 463 if (!is_recording_) 464 return; 465 RecordSending(app_id, receiver_id, message_id, "Received 'send error' msg", 466 std::string()); 467} 468 469} // namespace gcm 470