blob: e2a63681b1b04dd74f959184b0ab7a68795f3a04 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "missive/analytics/metrics.h"
#include <string>
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/memory/scoped_refptr.h>
#include <base/no_destructor.h>
#include <base/task/sequenced_task_runner.h>
#include <base/task/thread_pool.h>
#include <metrics/metrics_library.h>
namespace reporting::analytics {
namespace {
// The only `MetricsLibrary` instance. In production code, it never changes
// once set.
MetricsLibraryInterface* g_metrics_library = nullptr;
// The task runner on which metrics sends data. In production code, it never
// changes once set.
scoped_refptr<base::SequencedTaskRunner>& metrics_task_runner() {
static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>>
task_runner;
return *task_runner;
}
} // namespace
// static
void Metrics::Initialize() {
if (metrics_task_runner()) {
LOG(ERROR) << "Metrics already initialized or scheduled to be initialized. "
"skip initialization.";
return;
}
metrics_task_runner() = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
metrics_task_runner()->PostTask(FROM_HERE, base::BindOnce([]() {
g_metrics_library = new MetricsLibrary();
}));
}
// static
template <typename FuncType, typename... ArgTypes>
bool Metrics::PostUMATask(FuncType send_to_uma_func, ArgTypes... args) {
if (!metrics_task_runner()) {
LOG(ERROR) << "Task runner for metrics is not up. Not sending data to UMA.";
return false;
}
return metrics_task_runner()->PostTask(
FROM_HERE,
// Wrap send_to_uma_func with a void-return type lambda.
base::BindOnce(
[](FuncType send_to_uma_func, ArgTypes... args) -> void {
if (!g_metrics_library) {
// In theory, this block is only reachable in test.
LOG(ERROR)
<< "Metrics library not initialized. Skip sending to UMA.";
return;
}
const bool success =
(g_metrics_library->*send_to_uma_func)(args...);
LOG_IF(WARNING, !success) << "Send to UMA failed.";
},
send_to_uma_func, args...));
}
// static
bool Metrics::SendBoolToUMA(const std::string& name, bool sample) {
return PostUMATask(&MetricsLibraryInterface::SendBoolToUMA, name, sample);
}
// static
bool Metrics::SendSparseToUMA(const std::string& name, int sample) {
return PostUMATask(&MetricsLibraryInterface::SendSparseToUMA, name, sample);
}
// static
bool Metrics::SendEnumToUMA(const std::string& name,
int sample,
int exclusive_max) {
return PostUMATask(static_cast<bool (MetricsLibraryInterface::*)(
const std::string&, int, int)>(
&MetricsLibraryInterface::SendEnumToUMA),
name, sample, exclusive_max);
}
// static
bool Metrics::SendPercentageToUMA(const std::string& name, int sample) {
return PostUMATask(&MetricsLibraryInterface::SendPercentageToUMA, name,
sample);
}
// static
bool Metrics::SendLinearToUMA(const std::string& name, int sample, int max) {
return PostUMATask(&MetricsLibraryInterface::SendLinearToUMA, name, sample,
max);
}
// static
bool Metrics::SendToUMA(
const std::string& name, int sample, int min, int max, int nbuckets) {
return PostUMATask(&MetricsLibraryInterface::SendToUMA, name, sample, min,
max, nbuckets);
}
// static
MetricsLibraryInterface*& Metrics::GetMetricsLibraryForTest() {
return g_metrics_library;
}
// static
scoped_refptr<base::SequencedTaskRunner>&
Metrics::GetMetricsTaskRunnerForTest() {
return metrics_task_runner();
}
} // namespace reporting::analytics