| OLD | NEW |
| (Empty) |
| 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 "google_apis/gcm/monitoring/gcm_stats_recorder.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 | |
| 16 namespace gcm { | |
| 17 | |
| 18 const uint32 MAX_LOGGED_ACTIVITY_COUNT = 100; | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Insert an item to the front of deque while maintaining the size of the deque. | |
| 23 // Overflow item is discarded. | |
| 24 template <typename T> | |
| 25 T* 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. | |
| 35 std::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. | |
| 60 std::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. | |
| 81 std::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. | |
| 112 std::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 | |
| 143 GCMStatsRecorder::GCMStatsRecorder() : is_recording_(false), delegate_(NULL) { | |
| 144 } | |
| 145 | |
| 146 GCMStatsRecorder::~GCMStatsRecorder() { | |
| 147 } | |
| 148 | |
| 149 void GCMStatsRecorder::SetRecording(bool recording) { | |
| 150 is_recording_ = recording; | |
| 151 } | |
| 152 | |
| 153 void GCMStatsRecorder::SetDelegate(Delegate* delegate) { | |
| 154 delegate_ = delegate; | |
| 155 } | |
| 156 | |
| 157 void GCMStatsRecorder::Clear() { | |
| 158 checkin_activities_.clear(); | |
| 159 connection_activities_.clear(); | |
| 160 registration_activities_.clear(); | |
| 161 receiving_activities_.clear(); | |
| 162 sending_activities_.clear(); | |
| 163 } | |
| 164 | |
| 165 void GCMStatsRecorder::NotifyActivityRecorded() { | |
| 166 if (delegate_) | |
| 167 delegate_->OnActivityRecorded(); | |
| 168 } | |
| 169 | |
| 170 void GCMStatsRecorder::RecordCheckin( | |
| 171 const std::string& event, | |
| 172 const std::string& details) { | |
| 173 CheckinActivity data; | |
| 174 CheckinActivity* inserted_data = InsertCircularBuffer( | |
| 175 &checkin_activities_, data); | |
| 176 inserted_data->event = event; | |
| 177 inserted_data->details = details; | |
| 178 NotifyActivityRecorded(); | |
| 179 } | |
| 180 | |
| 181 void GCMStatsRecorder::RecordCheckinInitiated(uint64 android_id) { | |
| 182 if (!is_recording_) | |
| 183 return; | |
| 184 RecordCheckin("Checkin initiated", | |
| 185 base::StringPrintf("Android Id: %" PRIu64, android_id)); | |
| 186 } | |
| 187 | |
| 188 void GCMStatsRecorder::RecordCheckinDelayedDueToBackoff(int64 delay_msec) { | |
| 189 if (!is_recording_) | |
| 190 return; | |
| 191 RecordCheckin("Checkin backoff", | |
| 192 base::StringPrintf("Delayed for %" PRId64 " msec", | |
| 193 delay_msec)); | |
| 194 } | |
| 195 | |
| 196 void GCMStatsRecorder::RecordCheckinSuccess() { | |
| 197 if (!is_recording_) | |
| 198 return; | |
| 199 RecordCheckin("Checkin succeeded", std::string()); | |
| 200 } | |
| 201 | |
| 202 void GCMStatsRecorder::RecordCheckinFailure(std::string status, | |
| 203 bool will_retry) { | |
| 204 if (!is_recording_) | |
| 205 return; | |
| 206 RecordCheckin("Checkin failed", base::StringPrintf( | |
| 207 "%s.%s", | |
| 208 status.c_str(), | |
| 209 will_retry ? " Will retry." : "Will not retry.")); | |
| 210 } | |
| 211 | |
| 212 void GCMStatsRecorder::RecordConnection( | |
| 213 const std::string& event, | |
| 214 const std::string& details) { | |
| 215 ConnectionActivity data; | |
| 216 ConnectionActivity* inserted_data = InsertCircularBuffer( | |
| 217 &connection_activities_, data); | |
| 218 inserted_data->event = event; | |
| 219 inserted_data->details = details; | |
| 220 NotifyActivityRecorded(); | |
| 221 } | |
| 222 | |
| 223 void GCMStatsRecorder::RecordConnectionInitiated(const std::string& host) { | |
| 224 if (!is_recording_) | |
| 225 return; | |
| 226 RecordConnection("Connection initiated", host); | |
| 227 } | |
| 228 | |
| 229 void GCMStatsRecorder::RecordConnectionDelayedDueToBackoff(int64 delay_msec) { | |
| 230 if (!is_recording_) | |
| 231 return; | |
| 232 RecordConnection("Connection backoff", | |
| 233 base::StringPrintf("Delayed for %" PRId64 " msec", | |
| 234 delay_msec)); | |
| 235 } | |
| 236 | |
| 237 void GCMStatsRecorder::RecordConnectionSuccess() { | |
| 238 if (!is_recording_) | |
| 239 return; | |
| 240 RecordConnection("Connection succeeded", std::string()); | |
| 241 } | |
| 242 | |
| 243 void GCMStatsRecorder::RecordConnectionFailure(int network_error) { | |
| 244 if (!is_recording_) | |
| 245 return; | |
| 246 RecordConnection("Connection failed", | |
| 247 base::StringPrintf("With network error %d", network_error)); | |
| 248 } | |
| 249 | |
| 250 void GCMStatsRecorder::RecordConnectionResetSignaled( | |
| 251 ConnectionFactory::ConnectionResetReason reason) { | |
| 252 if (!is_recording_) | |
| 253 return; | |
| 254 RecordConnection("Connection reset", | |
| 255 GetConnectionResetReasonString(reason)); | |
| 256 } | |
| 257 | |
| 258 void GCMStatsRecorder::RecordRegistration( | |
| 259 const std::string& app_id, | |
| 260 const std::string& sender_ids, | |
| 261 const std::string& event, | |
| 262 const std::string& details) { | |
| 263 RegistrationActivity data; | |
| 264 RegistrationActivity* inserted_data = InsertCircularBuffer( | |
| 265 ®istration_activities_, data); | |
| 266 inserted_data->app_id = app_id; | |
| 267 inserted_data->sender_ids = sender_ids; | |
| 268 inserted_data->event = event; | |
| 269 inserted_data->details = details; | |
| 270 NotifyActivityRecorded(); | |
| 271 } | |
| 272 | |
| 273 void GCMStatsRecorder::RecordRegistrationSent( | |
| 274 const std::string& app_id, | |
| 275 const std::string& sender_ids) { | |
| 276 UMA_HISTOGRAM_COUNTS("GCM.RegistrationRequest", 1); | |
| 277 if (!is_recording_) | |
| 278 return; | |
| 279 RecordRegistration(app_id, sender_ids, | |
| 280 "Registration request sent", std::string()); | |
| 281 } | |
| 282 | |
| 283 void GCMStatsRecorder::RecordRegistrationResponse( | |
| 284 const std::string& app_id, | |
| 285 const std::vector<std::string>& sender_ids, | |
| 286 RegistrationRequest::Status status) { | |
| 287 if (!is_recording_) | |
| 288 return; | |
| 289 RecordRegistration(app_id, JoinString(sender_ids, ","), | |
| 290 "Registration response received", | |
| 291 GetRegistrationStatusString(status)); | |
| 292 } | |
| 293 | |
| 294 void GCMStatsRecorder::RecordRegistrationRetryRequested( | |
| 295 const std::string& app_id, | |
| 296 const std::vector<std::string>& sender_ids, | |
| 297 int retries_left) { | |
| 298 if (!is_recording_) | |
| 299 return; | |
| 300 RecordRegistration(app_id, JoinString(sender_ids, ","), | |
| 301 "Registration retry requested", | |
| 302 base::StringPrintf("Retries left: %d", retries_left)); | |
| 303 } | |
| 304 | |
| 305 void GCMStatsRecorder::RecordUnregistrationSent( | |
| 306 const std::string& app_id) { | |
| 307 UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRequest", 1); | |
| 308 if (!is_recording_) | |
| 309 return; | |
| 310 RecordRegistration(app_id, std::string(), "Unregistration request sent", | |
| 311 std::string()); | |
| 312 } | |
| 313 | |
| 314 void GCMStatsRecorder::RecordUnregistrationResponse( | |
| 315 const std::string& app_id, | |
| 316 UnregistrationRequest::Status status) { | |
| 317 if (!is_recording_) | |
| 318 return; | |
| 319 RecordRegistration(app_id, | |
| 320 std::string(), | |
| 321 "Unregistration response received", | |
| 322 GetUnregistrationStatusString(status)); | |
| 323 } | |
| 324 | |
| 325 void GCMStatsRecorder::RecordUnregistrationRetryDelayed( | |
| 326 const std::string& app_id, | |
| 327 int64 delay_msec) { | |
| 328 if (!is_recording_) | |
| 329 return; | |
| 330 RecordRegistration(app_id, | |
| 331 std::string(), | |
| 332 "Unregistration retry delayed", | |
| 333 base::StringPrintf("Delayed for %" PRId64 " msec", | |
| 334 delay_msec)); | |
| 335 } | |
| 336 | |
| 337 void GCMStatsRecorder::RecordReceiving( | |
| 338 const std::string& app_id, | |
| 339 const std::string& from, | |
| 340 int message_byte_size, | |
| 341 const std::string& event, | |
| 342 const std::string& details) { | |
| 343 ReceivingActivity data; | |
| 344 ReceivingActivity* inserted_data = InsertCircularBuffer( | |
| 345 &receiving_activities_, data); | |
| 346 inserted_data->app_id = app_id; | |
| 347 inserted_data->from = from; | |
| 348 inserted_data->message_byte_size = message_byte_size; | |
| 349 inserted_data->event = event; | |
| 350 inserted_data->details = details; | |
| 351 NotifyActivityRecorded(); | |
| 352 } | |
| 353 | |
| 354 void GCMStatsRecorder::RecordDataMessageReceived( | |
| 355 const std::string& app_id, | |
| 356 const std::string& from, | |
| 357 int message_byte_size, | |
| 358 bool to_registered_app, | |
| 359 ReceivedMessageType message_type) { | |
| 360 if (to_registered_app) | |
| 361 UMA_HISTOGRAM_COUNTS("GCM.DataMessageReceived", 1); | |
| 362 if (!is_recording_) | |
| 363 return; | |
| 364 if (!to_registered_app) { | |
| 365 RecordReceiving(app_id, from, message_byte_size, "Data msg received", | |
| 366 to_registered_app ? std::string() : | |
| 367 "No such registered app found"); | |
| 368 } else { | |
| 369 switch(message_type) { | |
| 370 case GCMStatsRecorder::DATA_MESSAGE: | |
| 371 RecordReceiving(app_id, from, message_byte_size, "Data msg received", | |
| 372 std::string()); | |
| 373 break; | |
| 374 case GCMStatsRecorder::DELETED_MESSAGES: | |
| 375 RecordReceiving(app_id, from, message_byte_size, "Data msg received", | |
| 376 "Message has been deleted on server"); | |
| 377 break; | |
| 378 default: | |
| 379 NOTREACHED(); | |
| 380 } | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 void GCMStatsRecorder::CollectActivities( | |
| 385 RecordedActivities* recorder_activities) const { | |
| 386 recorder_activities->checkin_activities.insert( | |
| 387 recorder_activities->checkin_activities.begin(), | |
| 388 checkin_activities_.begin(), | |
| 389 checkin_activities_.end()); | |
| 390 recorder_activities->connection_activities.insert( | |
| 391 recorder_activities->connection_activities.begin(), | |
| 392 connection_activities_.begin(), | |
| 393 connection_activities_.end()); | |
| 394 recorder_activities->registration_activities.insert( | |
| 395 recorder_activities->registration_activities.begin(), | |
| 396 registration_activities_.begin(), | |
| 397 registration_activities_.end()); | |
| 398 recorder_activities->receiving_activities.insert( | |
| 399 recorder_activities->receiving_activities.begin(), | |
| 400 receiving_activities_.begin(), | |
| 401 receiving_activities_.end()); | |
| 402 recorder_activities->sending_activities.insert( | |
| 403 recorder_activities->sending_activities.begin(), | |
| 404 sending_activities_.begin(), | |
| 405 sending_activities_.end()); | |
| 406 } | |
| 407 | |
| 408 void GCMStatsRecorder::RecordSending(const std::string& app_id, | |
| 409 const std::string& receiver_id, | |
| 410 const std::string& message_id, | |
| 411 const std::string& event, | |
| 412 const std::string& details) { | |
| 413 SendingActivity data; | |
| 414 SendingActivity* inserted_data = InsertCircularBuffer( | |
| 415 &sending_activities_, data); | |
| 416 inserted_data->app_id = app_id; | |
| 417 inserted_data->receiver_id = receiver_id; | |
| 418 inserted_data->message_id = message_id; | |
| 419 inserted_data->event = event; | |
| 420 inserted_data->details = details; | |
| 421 NotifyActivityRecorded(); | |
| 422 } | |
| 423 | |
| 424 void GCMStatsRecorder::RecordDataSentToWire( | |
| 425 const std::string& app_id, | |
| 426 const std::string& receiver_id, | |
| 427 const std::string& message_id, | |
| 428 int queued) { | |
| 429 if (!is_recording_) | |
| 430 return; | |
| 431 RecordSending(app_id, receiver_id, message_id, "Data msg sent to wire", | |
| 432 base::StringPrintf("Msg queued for %d seconds", queued)); | |
| 433 } | |
| 434 | |
| 435 void GCMStatsRecorder::RecordNotifySendStatus( | |
| 436 const std::string& app_id, | |
| 437 const std::string& receiver_id, | |
| 438 const std::string& message_id, | |
| 439 gcm::MCSClient::MessageSendStatus status, | |
| 440 int byte_size, | |
| 441 int ttl) { | |
| 442 UMA_HISTOGRAM_ENUMERATION("GCM.SendMessageStatus", status, | |
| 443 gcm::MCSClient::SEND_STATUS_COUNT); | |
| 444 if (!is_recording_) | |
| 445 return; | |
| 446 RecordSending( | |
| 447 app_id, | |
| 448 receiver_id, | |
| 449 message_id, | |
| 450 base::StringPrintf("SEND status: %s", | |
| 451 GetMessageSendStatusString(status).c_str()), | |
| 452 base::StringPrintf("Msg size: %d bytes, TTL: %d", byte_size, ttl)); | |
| 453 } | |
| 454 | |
| 455 void GCMStatsRecorder::RecordIncomingSendError( | |
| 456 const std::string& app_id, | |
| 457 const std::string& receiver_id, | |
| 458 const std::string& message_id) { | |
| 459 UMA_HISTOGRAM_COUNTS("GCM.IncomingSendErrors", 1); | |
| 460 if (!is_recording_) | |
| 461 return; | |
| 462 RecordSending(app_id, receiver_id, message_id, "Received 'send error' msg", | |
| 463 std::string()); | |
| 464 } | |
| 465 | |
| 466 } // namespace gcm | |
| OLD | NEW |