1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/reporting/client/report_queue.h"
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "base/strings/strcat.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status_macros.h"
#include "components/reporting/util/statusor.h"
namespace reporting {
namespace {
StatusOr<std::string> ValueToJson(base::Value::Dict record) {
std::string json_record;
if (!base::JSONWriter::Write(record, &json_record)) {
return base::unexpected(
Status(error::INVALID_ARGUMENT,
"Provided record was not convertable to a std::string"));
}
return json_record;
}
StatusOr<std::string> ProtoToString(
std::unique_ptr<const google::protobuf::MessageLite> record) {
std::string protobuf_record;
if (!record->SerializeToString(&protobuf_record)) {
return base::unexpected(
Status(error::INVALID_ARGUMENT,
"Unabled to serialize record to string. Most likely due to "
"unset required fields."));
}
return protobuf_record;
}
void EnqueueResponded(ReportQueue::EnqueueCallback callback,
Destination destination,
Status status) {
// Log the overall enqueue error status. Gives us insight to how the ERP is
// performing in general.
base::UmaHistogramEnumeration(ReportQueue::kEnqueueMetricsName, status.code(),
error::Code::MAX_VALUE);
// Log the type of enqueue error (if any) for this destination. Gives us
// insights as to what types of errors this destination experiences.
base::UmaHistogramEnumeration(
base::StrCat({ReportQueue::kEnqueueMetricsName, ".",
Destination_Name(destination)}),
status.code(), error::Code::MAX_VALUE);
// Log whether the enqueue succeeded or failed for this destination. Gives us
// insight as to whether one destination experiences more failures than
// others. If you find that a destination has more failures than other
// destinations, it could mean several things:
//
// 1. That destination gets much more traffic and is naturally going to
// experience more errors.
//
// 2. The code that enqueues records to that destination may be implemented
// incorrectly.
//
// To dive further, look up the `Browser.ERP.EventEnqueueResult<Destination>`
// UMA (logged above) to understand what types of errors the destination
// experiences most often.
const auto* const enqueue_destination_metrics_name =
status.ok() ? ReportQueue::kEnqueueSuccessDestinationMetricsName
: ReportQueue::kEnqueueFailedDestinationMetricsName;
base::UmaHistogramExactLinear(enqueue_destination_metrics_name,
static_cast<int>(destination),
Destination_ARRAYSIZE);
std::move(callback).Run(std::move(status));
}
} // namespace
ReportQueue::~ReportQueue() = default;
void ReportQueue::Enqueue(std::string record,
Priority priority,
ReportQueue::EnqueueCallback callback) const {
AddProducedRecord(
base::BindOnce([](std::string record)
-> StatusOr<std::string> { return std::move(record); },
std::move(record)),
priority,
base::BindOnce(&EnqueueResponded, std::move(callback), GetDestination()));
}
void ReportQueue::Enqueue(base::Value::Dict record,
Priority priority,
ReportQueue::EnqueueCallback callback) const {
AddProducedRecord(
base::BindOnce(&ValueToJson, std::move(record)), priority,
base::BindOnce(&EnqueueResponded, std::move(callback), GetDestination()));
}
void ReportQueue::Enqueue(
std::unique_ptr<const google::protobuf::MessageLite> record,
Priority priority,
ReportQueue::EnqueueCallback callback) const {
AddProducedRecord(
base::BindOnce(&ProtoToString, std::move(record)), priority,
base::BindOnce(&EnqueueResponded, std::move(callback), GetDestination()));
}
} // namespace reporting
|