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 |