| // 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 |