blob: 58f384124c165f6ee3ff2b4b33a8e97ce78798e6 [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
Kevin Marshall05e29bd2020-03-19 21:55:4414#include "base/fuchsia/fuchsia_logging.h"
Sharon Yangb2ff20e2020-06-19 12:54:0115#include "base/fuchsia/process_context.h"
Kevin Marshall05e29bd2020-03-19 21:55:4416#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;
Sharon Yangb2ff20e2020-06-19 12:54:0137 metrics_recorder_ = base::ComponentContextForProcess()
Kevin Marshall05e29bd2020-03-19 21:55:4438 ->svc()
39 ->Connect<fuchsia::legacymetrics::MetricsRecorder>();
40 metrics_recorder_.set_error_handler(fit::bind_member(
41 this, &LegacyMetricsClient::OnMetricsRecorderDisconnected));
Kevin Marshallaa7f5162020-06-04 23:32:3142 metrics_recorder_.events().OnCloseSoon =
43 fit::bind_member(this, &LegacyMetricsClient::OnCloseSoon);
Kevin Marshall05e29bd2020-03-19 21:55:4444 user_events_recorder_ = std::make_unique<LegacyMetricsUserActionRecorder>();
45 ScheduleNextReport();
46}
47
48void LegacyMetricsClient::SetReportAdditionalMetricsCallback(
49 ReportAdditionalMetricsCallback callback) {
50 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
51 DCHECK(!metrics_recorder_)
52 << "SetReportAdditionalMetricsCallback() must be called before Start().";
53 DCHECK(!report_additional_callback_);
54 DCHECK(callback);
55
56 report_additional_callback_ = std::move(callback);
57}
58
Kevin Marshallaa7f5162020-06-04 23:32:3159void LegacyMetricsClient::SetNotifyFlushCallback(NotifyFlushCallback callback) {
60 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
61 DCHECK(callback);
62 DCHECK(!metrics_recorder_)
63 << "SetNotifyFlushCallback() must be called before Start().";
64
65 notify_flush_callback_ = std::move(callback);
66}
67
Kevin Marshall05e29bd2020-03-19 21:55:4468void LegacyMetricsClient::ScheduleNextReport() {
Kevin Marshallaa7f5162020-06-04 23:32:3169 DCHECK(!is_flushing_);
70
Kevin Marshall05e29bd2020-03-19 21:55:4471 DVLOG(1) << "Scheduling next report in " << report_interval_.InSeconds()
72 << "seconds.";
Kevin Marshallebe60c42020-04-14 22:01:2473 timer_.Start(FROM_HERE, report_interval_, this,
74 &LegacyMetricsClient::StartReport);
Kevin Marshall05e29bd2020-03-19 21:55:4475}
76
Kevin Marshallebe60c42020-04-14 22:01:2477void LegacyMetricsClient::StartReport() {
78 if (!report_additional_callback_) {
79 Report({});
80 return;
81 }
82 report_additional_callback_.Run(
83 base::BindOnce(&LegacyMetricsClient::Report, weak_factory_.GetWeakPtr()));
84}
85
86void LegacyMetricsClient::Report(
87 std::vector<fuchsia::legacymetrics::Event> events) {
Kevin Marshall05e29bd2020-03-19 21:55:4488 DCHECK(metrics_recorder_);
Kevin Marshallebe60c42020-04-14 22:01:2489 DVLOG(1) << __func__ << " called.";
Kevin Marshall05e29bd2020-03-19 21:55:4490
91 // Include histograms.
92 for (auto& histogram : GetLegacyMetricsDeltas()) {
93 fuchsia::legacymetrics::Event histogram_event;
94 histogram_event.set_histogram(std::move(histogram));
95 events.push_back(std::move(histogram_event));
96 }
97
98 // Include user events.
99 if (user_events_recorder_->HasEvents()) {
100 for (auto& event : user_events_recorder_->TakeEvents()) {
101 fuchsia::legacymetrics::Event user_event;
102 user_event.set_user_action_event(std::move(event));
103 events.push_back(std::move(user_event));
104 }
105 }
106
Kevin Marshallaa7f5162020-06-04 23:32:31107 std::move(events.begin(), events.end(), std::back_inserter(to_send_));
Kevin Marshall05e29bd2020-03-19 21:55:44108
Kevin Marshallaa7f5162020-06-04 23:32:31109 DrainBuffer();
Kevin Marshallebe60c42020-04-14 22:01:24110}
111
Kevin Marshallaa7f5162020-06-04 23:32:31112void LegacyMetricsClient::DrainBuffer() {
113 DVLOG(1) << __func__ << " called.";
114
115 if (record_ack_pending_) {
116 // There is a Record() call already inflight. When it is acknowledged,
117 // buffer draining will continue.
Kevin Marshallebe60c42020-04-14 22:01:24118 return;
119 }
120
Kevin Marshallaa7f5162020-06-04 23:32:31121 if (to_send_.empty()) {
122 DVLOG(1) << "Buffer drained.";
123
124 if (is_flushing_) {
125 metrics_recorder_.Unbind();
126 } else {
127 ScheduleNextReport();
128 }
129
130 return;
131 }
132
133 // Since ordering doesn't matter, we can efficiently drain |to_send_| by
Kevin Marshallebe60c42020-04-14 22:01:24134 // repeatedly sending and truncating its tail.
Kevin Marshallaa7f5162020-06-04 23:32:31135 const size_t batch_size = std::min(to_send_.size(), kMaxBatchSize);
136 const size_t batch_start_idx = to_send_.size() - batch_size;
Kevin Marshallebe60c42020-04-14 22:01:24137 std::vector<fuchsia::legacymetrics::Event> batch;
138 batch.resize(batch_size);
Kevin Marshallaa7f5162020-06-04 23:32:31139 std::move(to_send_.begin() + batch_start_idx, to_send_.end(), batch.begin());
140 to_send_.resize(to_send_.size() - batch_size);
Kevin Marshallebe60c42020-04-14 22:01:24141
Kevin Marshallaa7f5162020-06-04 23:32:31142 record_ack_pending_ = true;
143 metrics_recorder_->Record(std::move(batch), [this]() {
144 record_ack_pending_ = false;
145 DrainBuffer();
146 });
Kevin Marshall05e29bd2020-03-19 21:55:44147}
148
149void LegacyMetricsClient::OnMetricsRecorderDisconnected(zx_status_t status) {
Wez1f809762020-06-11 19:08:44150 ZX_LOG(ERROR, status) << "MetricsRecorder connection lost.";
Kevin Marshall05e29bd2020-03-19 21:55:44151
152 // Stop recording & reporting user events.
153 user_events_recorder_.reset();
154 timer_.AbandonAndStop();
155}
156
Kevin Marshallaa7f5162020-06-04 23:32:31157void LegacyMetricsClient::OnCloseSoon() {
158 DVLOG(1) << __func__ << " called.";
159
160 timer_.AbandonAndStop();
161
162 is_flushing_ = true;
163 if (notify_flush_callback_) {
164 // Defer reporting until the flush operation has finished.
165 std::move(notify_flush_callback_)
166 .Run(base::BindOnce(&LegacyMetricsClient::StartReport,
167 weak_factory_.GetWeakPtr()));
168 } else {
169 StartReport();
170 }
171}
172
Kevin Marshall05e29bd2020-03-19 21:55:44173} // namespace cr_fuchsia