123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- // Copyright 2016 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 "remoting/base/telemetry_log_writer.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/containers/adapters.h"
- #include "base/json/json_string_value_serializer.h"
- #include "base/logging.h"
- #include "net/http/http_status_code.h"
- #include "net/traffic_annotation/network_traffic_annotation.h"
- #include "remoting/base/protobuf_http_client.h"
- #include "remoting/base/protobuf_http_request.h"
- #include "remoting/base/protobuf_http_request_config.h"
- #include "remoting/base/service_urls.h"
- #include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
- #include "services/network/public/cpp/shared_url_loader_factory.h"
- namespace remoting {
- namespace {
- const net::BackoffEntry::Policy kBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
- // Initial delay for exponential back-off in ms.
- 1000,
- // Factor by which the waiting time will be multiplied.
- 2,
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.5,
- // Maximum amount of time we are willing to delay our request in ms.
- 60000,
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
- // Starts with initial delay.
- false,
- };
- constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
- net::DefineNetworkTrafficAnnotation("remoting_telemetry_log_writer",
- R"(
- semantics {
- sender: "Chrome Remote Desktop"
- description:
- "Sends telemetry logs for Chrome Remote Desktop."
- trigger:
- "These requests are sent periodically by Chrome Remote Desktop "
- "(CRD) Android and iOS clients when a session is connected, i.e. "
- "CRD app is running and is connected to a host."
- data:
- "Anonymous usage statistics, which includes CRD host version, "
- "connection time, authentication type, connection error, and "
- "round trip latency."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: NO
- setting:
- "This request cannot be stopped in settings, but will not be sent "
- "if the user does not use Chrome Remote Desktop."
- policy_exception_justification:
- "Not implemented."
- })");
- constexpr char kCreateEventPath[] = "/v1/telemetry:createevent";
- }
- const int kMaxSendAttempts = 5;
- TelemetryLogWriter::TelemetryLogWriter(
- std::unique_ptr<OAuthTokenGetter> token_getter)
- : token_getter_(std::move(token_getter)), backoff_(&kBackoffPolicy) {
- DETACH_FROM_THREAD(thread_checker_);
- DCHECK(token_getter_);
- }
- TelemetryLogWriter::~TelemetryLogWriter() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- }
- void TelemetryLogWriter::Init(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(!http_client_);
- http_client_ = std::make_unique<ProtobufHttpClient>(
- ServiceUrls::GetInstance()->remoting_server_endpoint(),
- token_getter_.get(), url_loader_factory);
- }
- void TelemetryLogWriter::Log(const ChromotingEvent& entry) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- pending_entries_.push_back(entry);
- SendPendingEntries();
- }
- void TelemetryLogWriter::SendPendingEntries() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!sending_entries_.empty() || pending_entries_.empty()) {
- return;
- }
- apis::v1::CreateEventRequest request;
- while (!pending_entries_.empty()) {
- ChromotingEvent& entry = pending_entries_.front();
- DCHECK(entry.IsDataValid());
- *request.mutable_payload()->mutable_events()->Add() = entry.CreateProto();
- entry.IncrementSendAttempts();
- sending_entries_.push_back(std::move(entry));
- pending_entries_.pop_front();
- }
- base::TimeDelta time_until_release = backoff_.GetTimeUntilRelease();
- backoff_timer_.Start(
- FROM_HERE, time_until_release,
- base::BindOnce(&TelemetryLogWriter::DoSend, base::Unretained(this),
- std::move(request)));
- }
- void TelemetryLogWriter::DoSend(const apis::v1::CreateEventRequest& request) {
- DCHECK(http_client_);
- auto request_config =
- std::make_unique<ProtobufHttpRequestConfig>(kTrafficAnnotation);
- request_config->path = kCreateEventPath;
- request_config->request_message =
- std::make_unique<apis::v1::CreateEventRequest>(request);
- auto http_request =
- std::make_unique<ProtobufHttpRequest>(std::move(request_config));
- http_request->SetResponseCallback(base::BindOnce(
- &TelemetryLogWriter::OnSendLogResult, base::Unretained(this)));
- http_client_->ExecuteRequest(std::move(http_request));
- }
- void TelemetryLogWriter::OnSendLogResult(
- const ProtobufHttpStatus& status,
- std::unique_ptr<apis::v1::CreateEventResponse> response) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!status.ok()) {
- backoff_.InformOfRequest(false);
- LOG(WARNING) << "Error occur when sending logs to the telemetry server, "
- << "status: " << status.error_message();
- // Reverse iterating + push_front in order to restore the order of logs.
- for (auto& entry : base::Reversed(sending_entries_)) {
- if (entry.send_attempts() >= kMaxSendAttempts) {
- break;
- }
- pending_entries_.push_front(std::move(entry));
- }
- } else {
- backoff_.InformOfRequest(true);
- VLOG(1) << "Successfully sent " << sending_entries_.size()
- << " log(s) to telemetry server.";
- }
- sending_entries_.clear();
- SendPendingEntries();
- }
- bool TelemetryLogWriter::IsIdleForTesting() {
- return sending_entries_.empty() && pending_entries_.empty();
- }
- } // namespace remoting
|