blob: 21bde7afc7852e403792ea5f91214f55af8bc28a [file] [log] [blame]
Avi Drissmand878a5012022-09-12 19:13:301// Copyright 2021 The Chromium Authors
Ryan Keane5c34ef22021-07-19 19:10:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromecast/metrics/metrics_recorder.h"
6
7#include <stdint.h>
8
9#include <map>
10#include <string>
11#include <utility>
12#include <vector>
13
14#include "base/bind.h"
15#include "base/callback_helpers.h"
16#include "base/check.h"
17#include "base/containers/flat_map.h"
18#include "base/logging.h"
19#include "base/memory/ptr_util.h"
20#include "base/memory/ref_counted.h"
Ryan Keane5c34ef22021-07-19 19:10:3221#include "base/notreached.h"
22#include "base/observer_list.h"
Ryan Keane5c34ef22021-07-19 19:10:3223#include "base/synchronization/lock.h"
Patrick Monette643cdf62021-10-15 19:13:4224#include "base/task/single_thread_task_runner.h"
Ryan Keane5c34ef22021-07-19 19:10:3225#include "base/threading/thread_task_runner_handle.h"
26#include "base/time/time.h"
27#include "chromecast/metrics/cast_event_builder.h"
28#include "net/base/ip_address.h"
29
30namespace chromecast {
31
32namespace {
33
34bool IsLogOn(int verbose_log_level) {
35 // TODO(b/135640848): Determine a better way to log metrics for
36 // Fuchsia, without producing logspam during development.
37 return -verbose_log_level >= logging::GetMinLogLevel() ||
38 (DCHECK_IS_ON() && VLOG_IS_ON(verbose_log_level));
39}
40
41// A no-op dummy event builder, used when MetricsRecorder is nullptr.
42class DummyEventBuilder : public CastEventBuilder {
43 public:
44 // receiver::CastEventBuilder implementation
45 std::string GetName() override { return ""; }
46
47 CastEventBuilder& SetName(const std::string& name) override { return *this; }
48
49 CastEventBuilder& SetTime(const base::TimeTicks& time) override {
50 return *this;
51 }
52
53 CastEventBuilder& SetTimezoneId(const std::string& timezone_id) override {
54 return *this;
55 }
56
57 CastEventBuilder& SetAppId(const std::string& app_id) override {
58 return *this;
59 }
60
61 CastEventBuilder& SetRemoteAppId(const std::string& remote_app_id) override {
62 return *this;
63 }
64
65 CastEventBuilder& SetSessionId(const std::string& session_id) override {
66 return *this;
67 }
68
69 CastEventBuilder& SetSdkVersion(const std::string& sdk_version) override {
70 return *this;
71 }
72
73 CastEventBuilder& SetMplVersion(const std::string& mpl_version) override {
74 return *this;
75 }
76
77 CastEventBuilder& SetConnectionInfo(
78 const std::string& transport_connection_id,
79 const std::string& virtual_connection_id) override {
80 return *this;
81 }
82
83 CastEventBuilder& SetGroupUuid(const std::string& group_uuid) override {
84 return *this;
85 }
86
87 CastEventBuilder& SetExtraValue(int64_t extra_value) override {
88 return *this;
89 }
90
91 CastEventBuilder& SetConversationKey(
92 const std::string& conversation_key) override {
93 return *this;
94 }
95
96 CastEventBuilder& SetRequestId(int32_t request_id) override { return *this; }
97
98 CastEventBuilder& SetEventId(const std::string& event_id) override {
99 return *this;
100 }
101
102 CastEventBuilder& SetAoghRequestId(const std::string& request_id) override {
103 return *this;
104 }
105
106 CastEventBuilder& SetAoghLocalDeviceId(int64_t local_id) override {
107 return *this;
108 }
109
110 CastEventBuilder& SetAoghAgentId(const std::string& agent_id) override {
111 return *this;
112 }
113
Matt Swartwout9256eb42022-09-30 18:52:25114 CastEventBuilder& SetAoghStandardAgentId(
115 const std::string& agent_id) override {
116 return *this;
117 }
118
Ryan Keane5c34ef22021-07-19 19:10:32119 CastEventBuilder& SetUiVersion(const std::string& ui_version) override {
120 return *this;
121 }
122
123 CastEventBuilder& SetAuditReport(const std::string& audit_report) override {
124 return *this;
125 }
126
127 CastEventBuilder& SetDuoCoreVersion(int64_t version) override {
128 return *this;
129 }
130
131 CastEventBuilder& SetHotwordModelId(const std::string& model_id) override {
132 return *this;
133 }
134
135 CastEventBuilder& SetDiscoveryAppSubtype(const std::string& app_id) override {
136 return *this;
137 }
138
139 CastEventBuilder& SetDiscoveryNamespaceSubtype(
140 const std::string& namespace_hash) override {
141 return *this;
142 }
143
144 CastEventBuilder& SetDiscoverySender(
145 const net::IPAddressBytes& sender_ip) override {
146 return *this;
147 }
148
149 CastEventBuilder& SetDiscoveryUnicastFlag(bool uses_unicast) override {
150 return *this;
151 }
152
153 CastEventBuilder& SetFeatureVector(
154 const std::vector<float>& features) override {
155 return *this;
156 }
157
158 CastEventBuilder& AddMetadata(const std::string& name,
159 int64_t value) override {
160 return *this;
161 }
162
163 CastEventBuilder& SetLaunchFrom(LaunchFrom launch_from) override {
164 return *this;
165 }
166
167 CastEventBuilder& MergeFrom(
168 const ::metrics::CastLogsProto_CastEventProto* event_proto) override {
169 return *this;
170 }
171
172 ::metrics::CastLogsProto_CastEventProto* Build() override {
173 NOTREACHED();
174 return nullptr;
175 }
176};
177
178MetricsRecorder* g_instance = nullptr;
179
180} // namespace
181
182void RecordEventWithLogPrefix(const std::string& action,
183 std::unique_ptr<CastEventBuilder> event_builder,
184 int verbose_log_level,
185 const std::string& log_prefix) {
186 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
187 if (recorder && event_builder) {
188 recorder->RecordCastEvent(std::move(event_builder));
189 }
190
191 if (IsLogOn(verbose_log_level)) {
192 VLOG_STREAM(verbose_log_level) << log_prefix << action;
193 }
194}
195
196std::unique_ptr<CastEventBuilder> CreateCastEvent(const std::string& name) {
197 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
198 if (recorder) {
199 return recorder->CreateEventBuilder(name);
200 }
201 return std::make_unique<DummyEventBuilder>();
202}
203
204void RecordCastEvent(const std::string& log_name,
205 std::unique_ptr<CastEventBuilder> event_builder,
206 int verbose_log_level) {
207 RecordEventWithLogPrefix(log_name, std::move(event_builder),
208 verbose_log_level, "cast event: ");
209}
210
211void RecordAction(const std::string& action, int verbose_log_level) {
212 RecordEventWithLogPrefix(action, CreateCastEvent(action), verbose_log_level,
213 "Record action: ");
214}
215
216void LogAction(const std::string& action, int verbose_log_level) {
217 RecordEventWithLogPrefix(action, std::unique_ptr<CastEventBuilder>(),
218 verbose_log_level, "Log action: ");
219}
220
221void RecordHistogramTime(const std::string& name,
222 int sample,
223 int min,
224 int max,
225 int num_buckets,
226 int verbose_log_level) {
227 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
228 if (recorder) {
229 recorder->RecordHistogramTime(name, sample, min, max, num_buckets);
230 }
231
232 if (IsLogOn(verbose_log_level)) {
233 VLOG_STREAM(verbose_log_level)
234 << "Time histogram: " << name << ", sample=" << sample
235 << ", max=" << max << ", min=" << min
236 << ", num_buckets=" << num_buckets;
237 }
238}
239
240void RecordHistogramCount(const std::string& name,
241 int sample,
242 int min,
243 int max,
244 int num_buckets,
245 int verbose_log_level) {
246 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
247 if (recorder) {
248 recorder->RecordHistogramCount(name, sample, min, max, num_buckets);
249 }
250
251 if (IsLogOn(verbose_log_level)) {
252 VLOG_STREAM(verbose_log_level)
253 << "Count histogram: " << name << ", sample=" << sample
254 << ", max=" << max << ", min=" << min
255 << ", num_buckets=" << num_buckets;
256 }
257}
258
259void RecordHistogramEnum(const std::string& name,
260 int sample,
261 int boundary,
262 int verbose_log_level) {
263 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
264 if (recorder) {
265 recorder->RecordHistogramEnum(name, sample, boundary);
266 }
267
268 if (IsLogOn(verbose_log_level)) {
269 VLOG_STREAM(verbose_log_level)
270 << "Count histogram: " << name << ", sample=" << sample
271 << ", boundary=" << boundary;
272 }
273}
274
275struct MetricsRecorder::ObserverList {
276 base::ObserverList<Observer>::Unchecked list;
277};
278
279// static
280void MetricsRecorder::SetInstance(MetricsRecorder* recorder) {
281 g_instance = recorder;
282}
283
284// static
285MetricsRecorder* MetricsRecorder::GetInstance() {
286 return g_instance;
287}
288
289MetricsRecorder::MetricsRecorder()
290 : observer_list_(std::make_unique<ObserverList>()) {}
291
292MetricsRecorder::~MetricsRecorder() = default;
293
294void MetricsRecorder::NotifyOnPreUpload() {
295 for (auto& o : observer_list_->list)
296 o.OnPreUpload();
297}
298
299void MetricsRecorder::AddObserver(Observer* o) {
300 DCHECK(o);
301 observer_list_->list.AddObserver(o);
302}
303void MetricsRecorder::RemoveObserver(Observer* o) {
304 DCHECK(o);
305 observer_list_->list.RemoveObserver(o);
306}
307
308void RecordCastEvent(const std::string& event,
309 bool has_extra_value,
310 int64_t value,
311 MetricsRecorder* metrics_recorder) {
312 DCHECK(metrics_recorder);
313 auto event_builder = metrics_recorder->CreateEventBuilder(event);
314 if (has_extra_value) {
315 event_builder->SetExtraValue(value);
316 }
317 metrics_recorder->RecordCastEvent(std::move(event_builder));
318}
319
320void RecordCastEventWithMetadata(
321 const std::string& event,
322 const base::flat_map<std::string, int64_t>& settings_map,
323 MetricsRecorder* metrics_recorder) {
324 DCHECK(metrics_recorder);
325 auto event_builder = metrics_recorder->CreateEventBuilder(event);
326 for (const auto& kv_pair : settings_map) {
327 event_builder->AddMetadata(kv_pair.first, kv_pair.second);
328 }
329 metrics_recorder->RecordCastEvent(std::move(event_builder));
330}
331
332} // namespace chromecast