blob: a2d45a83ac8d326799a109bac078b269d1cae804 [file] [log] [blame]
Kevin Marshall05e29bd2020-03-19 21:55:441// Copyright 2020 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 "fuchsia/base/legacymetrics_client.h"
6
7#include <lib/fit/function.h>
8#include <lib/sys/cpp/component_context.h>
Kevin Marshallebe60c42020-04-14 22:01:249#include <algorithm>
Kevin Marshall05e29bd2020-03-19 21:55:4410#include <memory>
11#include <utility>
12#include <vector>
13
14#include "base/fuchsia/default_context.h"
15#include "base/fuchsia/fuchsia_logging.h"
16#include "base/logging.h"
17#include "base/threading/thread_task_runner_handle.h"
18#include "base/time/time.h"
19#include "fuchsia/base/legacymetrics_histogram_flattener.h"
20
21namespace cr_fuchsia {
22
Kevin Marshallebe60c42020-04-14 22:01:2423constexpr size_t LegacyMetricsClient::kMaxBatchSize;
24
Kevin Marshall05e29bd2020-03-19 21:55:4425LegacyMetricsClient::LegacyMetricsClient() = default;
26
27LegacyMetricsClient::~LegacyMetricsClient() {
28 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
29}
30
31void LegacyMetricsClient::Start(base::TimeDelta report_interval) {
32 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
33 DCHECK_GT(report_interval, base::TimeDelta::FromSeconds(0));
34 DCHECK(!metrics_recorder_) << "Start() called more than once.";
35
36 report_interval_ = report_interval;
37 metrics_recorder_ = base::fuchsia::ComponentContextForCurrentProcess()
38 ->svc()
39 ->Connect<fuchsia::legacymetrics::MetricsRecorder>();
40 metrics_recorder_.set_error_handler(fit::bind_member(
41 this, &LegacyMetricsClient::OnMetricsRecorderDisconnected));
42 user_events_recorder_ = std::make_unique<LegacyMetricsUserActionRecorder>();
43 ScheduleNextReport();
44}
45
46void LegacyMetricsClient::SetReportAdditionalMetricsCallback(
47 ReportAdditionalMetricsCallback callback) {
48 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
49 DCHECK(!metrics_recorder_)
50 << "SetReportAdditionalMetricsCallback() must be called before Start().";
51 DCHECK(!report_additional_callback_);
52 DCHECK(callback);
53
54 report_additional_callback_ = std::move(callback);
55}
56
57void LegacyMetricsClient::ScheduleNextReport() {
58 DVLOG(1) << "Scheduling next report in " << report_interval_.InSeconds()
59 << "seconds.";
Kevin Marshallebe60c42020-04-14 22:01:2460 timer_.Start(FROM_HERE, report_interval_, this,
61 &LegacyMetricsClient::StartReport);
Kevin Marshall05e29bd2020-03-19 21:55:4462}
63
Kevin Marshallebe60c42020-04-14 22:01:2464void LegacyMetricsClient::StartReport() {
65 if (!report_additional_callback_) {
66 Report({});
67 return;
68 }
69 report_additional_callback_.Run(
70 base::BindOnce(&LegacyMetricsClient::Report, weak_factory_.GetWeakPtr()));
71}
72
73void LegacyMetricsClient::Report(
74 std::vector<fuchsia::legacymetrics::Event> events) {
Kevin Marshall05e29bd2020-03-19 21:55:4475 DCHECK(metrics_recorder_);
Kevin Marshallebe60c42020-04-14 22:01:2476 DVLOG(1) << __func__ << " called.";
Kevin Marshall05e29bd2020-03-19 21:55:4477
78 // Include histograms.
79 for (auto& histogram : GetLegacyMetricsDeltas()) {
80 fuchsia::legacymetrics::Event histogram_event;
81 histogram_event.set_histogram(std::move(histogram));
82 events.push_back(std::move(histogram_event));
83 }
84
85 // Include user events.
86 if (user_events_recorder_->HasEvents()) {
87 for (auto& event : user_events_recorder_->TakeEvents()) {
88 fuchsia::legacymetrics::Event user_event;
89 user_event.set_user_action_event(std::move(event));
90 events.push_back(std::move(user_event));
91 }
92 }
93
94 if (events.empty()) {
95 ScheduleNextReport();
96 return;
97 }
98
Kevin Marshallebe60c42020-04-14 22:01:2499 DrainBuffer(std::move(events));
100}
101
102void LegacyMetricsClient::DrainBuffer(
103 std::vector<fuchsia::legacymetrics::Event> buffer) {
104 if (buffer.empty()) {
105 DVLOG(1) << "Buffer drained.";
Kevin Marshall05e29bd2020-03-19 21:55:44106 ScheduleNextReport();
Kevin Marshallebe60c42020-04-14 22:01:24107 return;
108 }
109
110 // Since ordering doesn't matter, we can efficiently drain |buffer| by
111 // repeatedly sending and truncating its tail.
112 const size_t batch_size = std::min(buffer.size(), kMaxBatchSize);
113 const size_t batch_start_idx = buffer.size() - batch_size;
114 std::vector<fuchsia::legacymetrics::Event> batch;
115 batch.resize(batch_size);
116 std::move(buffer.begin() + batch_start_idx, buffer.end(), batch.begin());
117 buffer.resize(buffer.size() - batch_size);
118
119 metrics_recorder_->Record(std::move(batch),
120 [this, buffer = std::move(buffer)]() mutable {
121 DrainBuffer(std::move(buffer));
122 });
Kevin Marshall05e29bd2020-03-19 21:55:44123}
124
125void LegacyMetricsClient::OnMetricsRecorderDisconnected(zx_status_t status) {
126 ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
127 << "MetricsRecorder connection lost.";
128
129 // Stop recording & reporting user events.
130 user_events_recorder_.reset();
131 timer_.AbandonAndStop();
132}
133
134} // namespace cr_fuchsia