telemetry_log_writer.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright 2016 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. #include "remoting/base/telemetry_log_writer.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/containers/adapters.h"
  9. #include "base/json/json_string_value_serializer.h"
  10. #include "base/logging.h"
  11. #include "net/http/http_status_code.h"
  12. #include "net/traffic_annotation/network_traffic_annotation.h"
  13. #include "remoting/base/protobuf_http_client.h"
  14. #include "remoting/base/protobuf_http_request.h"
  15. #include "remoting/base/protobuf_http_request_config.h"
  16. #include "remoting/base/service_urls.h"
  17. #include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
  18. #include "services/network/public/cpp/shared_url_loader_factory.h"
  19. namespace remoting {
  20. namespace {
  21. const net::BackoffEntry::Policy kBackoffPolicy = {
  22. // Number of initial errors (in sequence) to ignore before applying
  23. // exponential back-off rules.
  24. 0,
  25. // Initial delay for exponential back-off in ms.
  26. 1000,
  27. // Factor by which the waiting time will be multiplied.
  28. 2,
  29. // Fuzzing percentage. ex: 10% will spread requests randomly
  30. // between 90%-100% of the calculated time.
  31. 0.5,
  32. // Maximum amount of time we are willing to delay our request in ms.
  33. 60000,
  34. // Time to keep an entry from being discarded even when it
  35. // has no significant state, -1 to never discard.
  36. -1,
  37. // Starts with initial delay.
  38. false,
  39. };
  40. constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
  41. net::DefineNetworkTrafficAnnotation("remoting_telemetry_log_writer",
  42. R"(
  43. semantics {
  44. sender: "Chrome Remote Desktop"
  45. description:
  46. "Sends telemetry logs for Chrome Remote Desktop."
  47. trigger:
  48. "These requests are sent periodically by Chrome Remote Desktop "
  49. "(CRD) Android and iOS clients when a session is connected, i.e. "
  50. "CRD app is running and is connected to a host."
  51. data:
  52. "Anonymous usage statistics, which includes CRD host version, "
  53. "connection time, authentication type, connection error, and "
  54. "round trip latency."
  55. destination: GOOGLE_OWNED_SERVICE
  56. }
  57. policy {
  58. cookies_allowed: NO
  59. setting:
  60. "This request cannot be stopped in settings, but will not be sent "
  61. "if the user does not use Chrome Remote Desktop."
  62. policy_exception_justification:
  63. "Not implemented."
  64. })");
  65. constexpr char kCreateEventPath[] = "/v1/telemetry:createevent";
  66. }
  67. const int kMaxSendAttempts = 5;
  68. TelemetryLogWriter::TelemetryLogWriter(
  69. std::unique_ptr<OAuthTokenGetter> token_getter)
  70. : token_getter_(std::move(token_getter)), backoff_(&kBackoffPolicy) {
  71. DETACH_FROM_THREAD(thread_checker_);
  72. DCHECK(token_getter_);
  73. }
  74. TelemetryLogWriter::~TelemetryLogWriter() {
  75. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  76. }
  77. void TelemetryLogWriter::Init(
  78. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
  79. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  80. DCHECK(!http_client_);
  81. http_client_ = std::make_unique<ProtobufHttpClient>(
  82. ServiceUrls::GetInstance()->remoting_server_endpoint(),
  83. token_getter_.get(), url_loader_factory);
  84. }
  85. void TelemetryLogWriter::Log(const ChromotingEvent& entry) {
  86. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  87. pending_entries_.push_back(entry);
  88. SendPendingEntries();
  89. }
  90. void TelemetryLogWriter::SendPendingEntries() {
  91. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  92. if (!sending_entries_.empty() || pending_entries_.empty()) {
  93. return;
  94. }
  95. apis::v1::CreateEventRequest request;
  96. while (!pending_entries_.empty()) {
  97. ChromotingEvent& entry = pending_entries_.front();
  98. DCHECK(entry.IsDataValid());
  99. *request.mutable_payload()->mutable_events()->Add() = entry.CreateProto();
  100. entry.IncrementSendAttempts();
  101. sending_entries_.push_back(std::move(entry));
  102. pending_entries_.pop_front();
  103. }
  104. base::TimeDelta time_until_release = backoff_.GetTimeUntilRelease();
  105. backoff_timer_.Start(
  106. FROM_HERE, time_until_release,
  107. base::BindOnce(&TelemetryLogWriter::DoSend, base::Unretained(this),
  108. std::move(request)));
  109. }
  110. void TelemetryLogWriter::DoSend(const apis::v1::CreateEventRequest& request) {
  111. DCHECK(http_client_);
  112. auto request_config =
  113. std::make_unique<ProtobufHttpRequestConfig>(kTrafficAnnotation);
  114. request_config->path = kCreateEventPath;
  115. request_config->request_message =
  116. std::make_unique<apis::v1::CreateEventRequest>(request);
  117. auto http_request =
  118. std::make_unique<ProtobufHttpRequest>(std::move(request_config));
  119. http_request->SetResponseCallback(base::BindOnce(
  120. &TelemetryLogWriter::OnSendLogResult, base::Unretained(this)));
  121. http_client_->ExecuteRequest(std::move(http_request));
  122. }
  123. void TelemetryLogWriter::OnSendLogResult(
  124. const ProtobufHttpStatus& status,
  125. std::unique_ptr<apis::v1::CreateEventResponse> response) {
  126. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  127. if (!status.ok()) {
  128. backoff_.InformOfRequest(false);
  129. LOG(WARNING) << "Error occur when sending logs to the telemetry server, "
  130. << "status: " << status.error_message();
  131. // Reverse iterating + push_front in order to restore the order of logs.
  132. for (auto& entry : base::Reversed(sending_entries_)) {
  133. if (entry.send_attempts() >= kMaxSendAttempts) {
  134. break;
  135. }
  136. pending_entries_.push_front(std::move(entry));
  137. }
  138. } else {
  139. backoff_.InformOfRequest(true);
  140. VLOG(1) << "Successfully sent " << sending_entries_.size()
  141. << " log(s) to telemetry server.";
  142. }
  143. sending_entries_.clear();
  144. SendPendingEntries();
  145. }
  146. bool TelemetryLogWriter::IsIdleForTesting() {
  147. return sending_entries_.empty() && pending_entries_.empty();
  148. }
  149. } // namespace remoting