blob: d40559307d58c37fca774bfb53a528020c548abe [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
114 CastEventBuilder& SetUiVersion(const std::string& ui_version) override {
115 return *this;
116 }
117
118 CastEventBuilder& SetAuditReport(const std::string& audit_report) override {
119 return *this;
120 }
121
122 CastEventBuilder& SetDuoCoreVersion(int64_t version) override {
123 return *this;
124 }
125
126 CastEventBuilder& SetHotwordModelId(const std::string& model_id) override {
127 return *this;
128 }
129
130 CastEventBuilder& SetDiscoveryAppSubtype(const std::string& app_id) override {
131 return *this;
132 }
133
134 CastEventBuilder& SetDiscoveryNamespaceSubtype(
135 const std::string& namespace_hash) override {
136 return *this;
137 }
138
139 CastEventBuilder& SetDiscoverySender(
140 const net::IPAddressBytes& sender_ip) override {
141 return *this;
142 }
143
144 CastEventBuilder& SetDiscoveryUnicastFlag(bool uses_unicast) override {
145 return *this;
146 }
147
148 CastEventBuilder& SetFeatureVector(
149 const std::vector<float>& features) override {
150 return *this;
151 }
152
153 CastEventBuilder& AddMetadata(const std::string& name,
154 int64_t value) override {
155 return *this;
156 }
157
158 CastEventBuilder& SetLaunchFrom(LaunchFrom launch_from) override {
159 return *this;
160 }
161
162 CastEventBuilder& MergeFrom(
163 const ::metrics::CastLogsProto_CastEventProto* event_proto) override {
164 return *this;
165 }
166
167 ::metrics::CastLogsProto_CastEventProto* Build() override {
168 NOTREACHED();
169 return nullptr;
170 }
171};
172
173MetricsRecorder* g_instance = nullptr;
174
175} // namespace
176
177void RecordEventWithLogPrefix(const std::string& action,
178 std::unique_ptr<CastEventBuilder> event_builder,
179 int verbose_log_level,
180 const std::string& log_prefix) {
181 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
182 if (recorder && event_builder) {
183 recorder->RecordCastEvent(std::move(event_builder));
184 }
185
186 if (IsLogOn(verbose_log_level)) {
187 VLOG_STREAM(verbose_log_level) << log_prefix << action;
188 }
189}
190
191std::unique_ptr<CastEventBuilder> CreateCastEvent(const std::string& name) {
192 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
193 if (recorder) {
194 return recorder->CreateEventBuilder(name);
195 }
196 return std::make_unique<DummyEventBuilder>();
197}
198
199void RecordCastEvent(const std::string& log_name,
200 std::unique_ptr<CastEventBuilder> event_builder,
201 int verbose_log_level) {
202 RecordEventWithLogPrefix(log_name, std::move(event_builder),
203 verbose_log_level, "cast event: ");
204}
205
206void RecordAction(const std::string& action, int verbose_log_level) {
207 RecordEventWithLogPrefix(action, CreateCastEvent(action), verbose_log_level,
208 "Record action: ");
209}
210
211void LogAction(const std::string& action, int verbose_log_level) {
212 RecordEventWithLogPrefix(action, std::unique_ptr<CastEventBuilder>(),
213 verbose_log_level, "Log action: ");
214}
215
216void RecordHistogramTime(const std::string& name,
217 int sample,
218 int min,
219 int max,
220 int num_buckets,
221 int verbose_log_level) {
222 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
223 if (recorder) {
224 recorder->RecordHistogramTime(name, sample, min, max, num_buckets);
225 }
226
227 if (IsLogOn(verbose_log_level)) {
228 VLOG_STREAM(verbose_log_level)
229 << "Time histogram: " << name << ", sample=" << sample
230 << ", max=" << max << ", min=" << min
231 << ", num_buckets=" << num_buckets;
232 }
233}
234
235void RecordHistogramCount(const std::string& name,
236 int sample,
237 int min,
238 int max,
239 int num_buckets,
240 int verbose_log_level) {
241 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
242 if (recorder) {
243 recorder->RecordHistogramCount(name, sample, min, max, num_buckets);
244 }
245
246 if (IsLogOn(verbose_log_level)) {
247 VLOG_STREAM(verbose_log_level)
248 << "Count histogram: " << name << ", sample=" << sample
249 << ", max=" << max << ", min=" << min
250 << ", num_buckets=" << num_buckets;
251 }
252}
253
254void RecordHistogramEnum(const std::string& name,
255 int sample,
256 int boundary,
257 int verbose_log_level) {
258 MetricsRecorder* recorder = MetricsRecorder::GetInstance();
259 if (recorder) {
260 recorder->RecordHistogramEnum(name, sample, boundary);
261 }
262
263 if (IsLogOn(verbose_log_level)) {
264 VLOG_STREAM(verbose_log_level)
265 << "Count histogram: " << name << ", sample=" << sample
266 << ", boundary=" << boundary;
267 }
268}
269
270struct MetricsRecorder::ObserverList {
271 base::ObserverList<Observer>::Unchecked list;
272};
273
274// static
275void MetricsRecorder::SetInstance(MetricsRecorder* recorder) {
276 g_instance = recorder;
277}
278
279// static
280MetricsRecorder* MetricsRecorder::GetInstance() {
281 return g_instance;
282}
283
284MetricsRecorder::MetricsRecorder()
285 : observer_list_(std::make_unique<ObserverList>()) {}
286
287MetricsRecorder::~MetricsRecorder() = default;
288
289void MetricsRecorder::NotifyOnPreUpload() {
290 for (auto& o : observer_list_->list)
291 o.OnPreUpload();
292}
293
294void MetricsRecorder::AddObserver(Observer* o) {
295 DCHECK(o);
296 observer_list_->list.AddObserver(o);
297}
298void MetricsRecorder::RemoveObserver(Observer* o) {
299 DCHECK(o);
300 observer_list_->list.RemoveObserver(o);
301}
302
303void RecordCastEvent(const std::string& event,
304 bool has_extra_value,
305 int64_t value,
306 MetricsRecorder* metrics_recorder) {
307 DCHECK(metrics_recorder);
308 auto event_builder = metrics_recorder->CreateEventBuilder(event);
309 if (has_extra_value) {
310 event_builder->SetExtraValue(value);
311 }
312 metrics_recorder->RecordCastEvent(std::move(event_builder));
313}
314
315void RecordCastEventWithMetadata(
316 const std::string& event,
317 const base::flat_map<std::string, int64_t>& settings_map,
318 MetricsRecorder* metrics_recorder) {
319 DCHECK(metrics_recorder);
320 auto event_builder = metrics_recorder->CreateEventBuilder(event);
321 for (const auto& kv_pair : settings_map) {
322 event_builder->AddMetadata(kv_pair.first, kv_pair.second);
323 }
324 metrics_recorder->RecordCastEvent(std::move(event_builder));
325}
326
327} // namespace chromecast