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