Add global MetricsLogger and export APIs

Bug: b/246095034
Change-Id: Id4cab9352b2155d967d0604b830fd87511675789
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/276603
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38183}
diff --git a/api/test/metrics/BUILD.gn b/api/test/metrics/BUILD.gn
index 4369800..64e7c1c 100644
--- a/api/test/metrics/BUILD.gn
+++ b/api/test/metrics/BUILD.gn
@@ -27,6 +27,7 @@
     testonly = true
 
     deps = [
+      ":global_metrics_logger_and_exporter_test",
       ":metrics_logger_and_exporter_test",
       ":metrics_logger_test",
       ":print_result_proxy_metrics_exporter_test",
@@ -187,6 +188,7 @@
   ]
   deps = [
     ":metrics_exporter",
+    ":metrics_logger",
     ":metrics_logger_and_exporter",
     "../../../rtc_base:checks",
     "../../../system_wrappers",
@@ -243,6 +245,21 @@
     absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
   }
 
+  rtc_library("global_metrics_logger_and_exporter_test") {
+    testonly = true
+    sources = [ "global_metrics_logger_and_exporter_test.cc" ]
+    deps = [
+      ":global_metrics_logger_and_exporter",
+      ":metric",
+      ":metrics_exporter",
+      ":metrics_logger",
+      ":metrics_logger_and_exporter",
+      "../../../system_wrappers",
+      "../../../test:test_support",
+    ]
+    absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+  }
+
   if (rtc_enable_protobuf) {
     rtc_library("metrics_set_proto_file_exporter_test") {
       testonly = true
diff --git a/api/test/metrics/global_metrics_logger_and_exporter.cc b/api/test/metrics/global_metrics_logger_and_exporter.cc
index d1de0c5..476dd4d 100644
--- a/api/test/metrics/global_metrics_logger_and_exporter.cc
+++ b/api/test/metrics/global_metrics_logger_and_exporter.cc
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "api/test/metrics/metrics_exporter.h"
+#include "api/test/metrics/metrics_logger.h"
 #include "api/test/metrics/metrics_logger_and_exporter.h"
 #include "rtc_base/checks.h"
 #include "system_wrappers/include/clock.h"
@@ -26,6 +27,23 @@
 
 }  // namespace
 
+MetricsLogger* GetGlobalMetricsLogger() {
+  static MetricsLogger* logger_ =
+      new DefaultMetricsLogger(Clock::GetRealTimeClock());
+  return logger_;
+}
+
+bool ExportPerfMetric(MetricsLogger& logger,
+                      std::vector<std::unique_ptr<MetricsExporter>> exporters) {
+  std::vector<Metric> metrics = logger.GetCollectedMetrics();
+  bool success = true;
+  for (auto& exporter : exporters) {
+    bool export_result = exporter->Export(metrics);
+    success = success && export_result;
+  }
+  return success;
+}
+
 MetricsLoggerAndExporter* GetGlobalMetricsLoggerAndExporter() {
   return global_metrics_logger_and_exporter;
 }
diff --git a/api/test/metrics/global_metrics_logger_and_exporter.h b/api/test/metrics/global_metrics_logger_and_exporter.h
index 1029545..9032eb1 100644
--- a/api/test/metrics/global_metrics_logger_and_exporter.h
+++ b/api/test/metrics/global_metrics_logger_and_exporter.h
@@ -20,6 +20,12 @@
 namespace webrtc {
 namespace test {
 
+// Returns non-null global `MetricsLogger` to log metrics.
+MetricsLogger* GetGlobalMetricsLogger();
+
+bool ExportPerfMetric(MetricsLogger& logger,
+                      std::vector<std::unique_ptr<MetricsExporter>> exporters);
+
 // Returns current global `MetricsLoggerAndExporter`. Returns `nullptr` if there
 // is global instance wasn't initialized.
 MetricsLoggerAndExporter* GetGlobalMetricsLoggerAndExporter();
diff --git a/api/test/metrics/global_metrics_logger_and_exporter_test.cc b/api/test/metrics/global_metrics_logger_and_exporter_test.cc
new file mode 100644
index 0000000..567b3da
--- /dev/null
+++ b/api/test/metrics/global_metrics_logger_and_exporter_test.cc
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/test/metrics/global_metrics_logger_and_exporter.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/test/metrics/metric.h"
+#include "api/test/metrics/metrics_exporter.h"
+#include "api/test/metrics/metrics_logger.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+
+std::map<std::string, std::string> DefaultMetadata() {
+  return std::map<std::string, std::string>{{"key", "value"}};
+}
+
+struct TestMetricsExporterFactory {
+ public:
+  std::unique_ptr<MetricsExporter> CreateExporter() {
+    return std::make_unique<TestMetricsExporter>(this, /*export_result=*/true);
+  }
+
+  std::unique_ptr<MetricsExporter> CreateFailureExporter() {
+    return std::make_unique<TestMetricsExporter>(this, /*export_result=*/false);
+  }
+
+  std::vector<Metric> exported_metrics;
+
+ private:
+  class TestMetricsExporter : public MetricsExporter {
+   public:
+    TestMetricsExporter(TestMetricsExporterFactory* factory, bool export_result)
+        : factory_(factory), export_result_(export_result) {}
+    ~TestMetricsExporter() override = default;
+
+    bool Export(rtc::ArrayView<const Metric> metrics) override {
+      factory_->exported_metrics =
+          std::vector<Metric>(metrics.begin(), metrics.end());
+      return export_result_;
+    }
+
+    TestMetricsExporterFactory* factory_;
+    bool export_result_;
+  };
+};
+
+TEST(ExportPerfMetricTest, CollectedMetricsAreExporter) {
+  TestMetricsExporterFactory exporter_factory;
+
+  DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+  logger.LogSingleValueMetric(
+      "metric_name", "test_case_name",
+      /*value=*/10, Unit::kMilliseconds, ImprovementDirection::kBiggerIsBetter,
+      std::map<std::string, std::string>{{"key", "value"}});
+
+  std::vector<std::unique_ptr<MetricsExporter>> exporters;
+  exporters.push_back(exporter_factory.CreateExporter());
+  ASSERT_TRUE(ExportPerfMetric(logger, std::move(exporters)));
+
+  std::vector<Metric> metrics = exporter_factory.exported_metrics;
+  ASSERT_THAT(metrics.size(), Eq(1lu));
+  const Metric& metric = metrics[0];
+  EXPECT_THAT(metric.name, Eq("metric_name"));
+  EXPECT_THAT(metric.test_case, Eq("test_case_name"));
+  EXPECT_THAT(metric.unit, Eq(Unit::kMilliseconds));
+  EXPECT_THAT(metric.improvement_direction,
+              Eq(ImprovementDirection::kBiggerIsBetter));
+  EXPECT_THAT(metric.metric_metadata,
+              Eq(std::map<std::string, std::string>{{"key", "value"}}));
+  ASSERT_THAT(metric.time_series.samples.size(), Eq(1lu));
+  EXPECT_THAT(metric.time_series.samples[0].value, Eq(10.0));
+  EXPECT_THAT(metric.time_series.samples[0].sample_metadata,
+              Eq(std::map<std::string, std::string>{}));
+  ASSERT_THAT(metric.stats.mean, absl::optional<double>(10.0));
+  ASSERT_THAT(metric.stats.stddev, absl::nullopt);
+  ASSERT_THAT(metric.stats.min, absl::optional<double>(10.0));
+  ASSERT_THAT(metric.stats.max, absl::optional<double>(10.0));
+}
+
+TEST(ExportPerfMetricTest, OneFailedExporterDoesNotPreventExportToOthers) {
+  TestMetricsExporterFactory exporter_factory1;
+  TestMetricsExporterFactory exporter_factory2;
+  TestMetricsExporterFactory exporter_factory3;
+
+  DefaultMetricsLogger logger(Clock::GetRealTimeClock());
+  logger.LogSingleValueMetric("metric_name", "test_case_name",
+                              /*value=*/10, Unit::kMilliseconds,
+                              ImprovementDirection::kBiggerIsBetter,
+                              DefaultMetadata());
+
+  std::vector<std::unique_ptr<MetricsExporter>> exporters;
+  exporters.push_back(exporter_factory1.CreateExporter());
+  exporters.push_back(exporter_factory2.CreateFailureExporter());
+  exporters.push_back(exporter_factory3.CreateExporter());
+  ASSERT_FALSE(ExportPerfMetric(logger, std::move(exporters)));
+
+  std::vector<Metric> metrics1 = exporter_factory1.exported_metrics;
+  std::vector<Metric> metrics2 = exporter_factory2.exported_metrics;
+  std::vector<Metric> metrics3 = exporter_factory3.exported_metrics;
+  ASSERT_THAT(metrics1.size(), Eq(1lu))
+      << metrics1[0].name << "; " << metrics1[1].name;
+  EXPECT_THAT(metrics1[0].name, Eq("metric_name"));
+  ASSERT_THAT(metrics2.size(), Eq(1lu));
+  EXPECT_THAT(metrics2[0].name, Eq("metric_name"));
+  ASSERT_THAT(metrics3.size(), Eq(1lu));
+  EXPECT_THAT(metrics3[0].name, Eq("metric_name"));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace webrtc