Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit ebdb4db

Browse files
author
Ian Sturdy
authored
Changes to the stats exporter interface (#59)
* Add an interface for pull exporters. The present exporter interface is unsuited for pull exporters--they need to store data from timed exports, and have no robust means of telling when a view has been unregistered and should no longer be exporting. This adds a direct interface to retrieve fresh data from registered views. Since accessing the ViewData only requires read-only access to the registered views, exporters using this pull interface will not contend with the timed push exports. * Disallow registering non-cumulative views with the stats exporter.
1 parent efdf740 commit ebdb4db

File tree

7 files changed

+68
-23
lines changed

7 files changed

+68
-23
lines changed

opencensus/exporters/stats/stackdriver/internal/stackdriver_exporter.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,6 @@ void StackdriverExporter::Handler::ExportViewData(
7373
const opencensus::stats::ViewDescriptor& descriptor,
7474
const opencensus::stats::ViewData& data) {
7575
absl::MutexLock l(&mu_);
76-
// Stackdriver does not support interval aggregation.
77-
if (descriptor.aggregation_window().type() !=
78-
opencensus::stats::AggregationWindow::Type::kCumulative) {
79-
return;
80-
}
8176
if (!MaybeRegisterView(descriptor)) {
8277
return;
8378
}
@@ -134,7 +129,7 @@ bool StackdriverExporter::Handler::MaybeRegisterView(
134129
// static
135130
void StackdriverExporter::Register(absl::string_view project_id,
136131
absl::string_view opencensus_task) {
137-
opencensus::stats::StatsExporter::RegisterHandler(absl::WrapUnique(
132+
opencensus::stats::StatsExporter::RegisterPushHandler(absl::WrapUnique(
138133
new StackdriverExporter::Handler(project_id, opencensus_task)));
139134
}
140135

opencensus/exporters/stats/stdout/internal/stdout_exporter.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class StdoutExporter::Handler
5555

5656
// static
5757
void StdoutExporter::Register() {
58-
opencensus::stats::StatsExporter::RegisterHandler(
58+
opencensus::stats::StatsExporter::RegisterPushHandler(
5959
absl::make_unique<StdoutExporter::Handler>());
6060
}
6161

opencensus/stats/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ cc_test(
183183
deps = [
184184
":core",
185185
":export",
186+
":recording",
186187
"@com_google_absl//absl/memory",
187188
"@com_google_absl//absl/time",
188189
"@com_google_googletest//:gtest_main",

opencensus/stats/examples/exporter_example.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ opencensus::stats::MeasureDouble FooUsage() {
3838
class ExampleExporter : public opencensus::stats::StatsExporter::Handler {
3939
public:
4040
static void Register() {
41-
opencensus::stats::StatsExporter::RegisterHandler(
41+
opencensus::stats::StatsExporter::RegisterPushHandler(
4242
absl::make_unique<ExampleExporter>());
4343
}
4444

opencensus/stats/internal/stats_exporter.cc

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414

1515
#include "opencensus/stats/stats_exporter.h"
1616

17+
#include <iostream>
1718
#include <thread> // NOLINT
19+
#include <utility>
20+
#include <vector>
1821

1922
#include "absl/memory/memory.h"
2023
#include "absl/synchronization/mutex.h"
2124
#include "absl/time/clock.h"
2225
#include "absl/time/time.h"
26+
#include "opencensus/stats/internal/aggregation_window.h"
2327

2428
namespace opencensus {
2529
namespace stats {
@@ -45,16 +49,26 @@ class StatsExporterImpl {
4549
// Adds a handler, which cannot be subsequently removed (except by
4650
// ClearHandlersForTesting()). The background thread is started when the
4751
// first handler is registered.
48-
void RegisterHandler(std::unique_ptr<StatsExporter::Handler> handler) {
52+
void RegisterPushHandler(std::unique_ptr<StatsExporter::Handler> handler) {
4953
absl::MutexLock l(&mu_);
5054
handlers_.push_back(std::move(handler));
5155
if (!thread_started_) {
5256
StartExportThread();
5357
}
5458
}
5559

60+
std::vector<std::pair<ViewDescriptor, ViewData>> GetViewData() {
61+
absl::ReaderMutexLock l(&mu_);
62+
std::vector<std::pair<ViewDescriptor, ViewData>> data;
63+
data.reserve(views_.size());
64+
for (const auto& view : views_) {
65+
data.emplace_back(view.second->descriptor(), view.second->GetData());
66+
}
67+
return data;
68+
}
69+
5670
void Export() {
57-
absl::MutexLock l(&mu_);
71+
absl::ReaderMutexLock l(&mu_);
5872
for (const auto& view : views_) {
5973
SendToHandlers(view.second->descriptor(), view.second->GetData());
6074
}
@@ -106,15 +120,24 @@ class StatsExporterImpl {
106120
};
107121

108122
void StatsExporter::AddView(const ViewDescriptor& view) {
109-
StatsExporterImpl::Get()->AddView(view);
123+
if (view.aggregation_window().type() ==
124+
AggregationWindow::Type::kCumulative) {
125+
StatsExporterImpl::Get()->AddView(view);
126+
} else {
127+
std::cerr << "Only cumulative views may be registered for export.\n";
128+
}
110129
}
111130

112131
void StatsExporter::RemoveView(absl::string_view name) {
113132
StatsExporterImpl::Get()->RemoveView(name);
114133
}
115134

116-
void StatsExporter::RegisterHandler(std::unique_ptr<Handler> handler) {
117-
StatsExporterImpl::Get()->RegisterHandler(std::move(handler));
135+
void StatsExporter::RegisterPushHandler(std::unique_ptr<Handler> handler) {
136+
StatsExporterImpl::Get()->RegisterPushHandler(std::move(handler));
137+
}
138+
139+
std::vector<std::pair<ViewDescriptor, ViewData>> StatsExporter::GetViewData() {
140+
return StatsExporterImpl::Get()->GetViewData();
118141
}
119142

120143
void StatsExporter::ExportForTesting() { StatsExporterImpl::Get()->Export(); }

opencensus/stats/internal/stats_exporter_test.cc

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
#include "opencensus/stats/stats_exporter.h"
1616

1717
#include <cstdint>
18+
#include <utility>
1819
#include <vector>
1920

2021
#include "absl/memory/memory.h"
2122
#include "absl/time/clock.h"
2223
#include "absl/time/time.h"
2324
#include "gmock/gmock.h"
2425
#include "gtest/gtest.h"
26+
#include "opencensus/stats/internal/set_aggregation_window.h"
2527
#include "opencensus/stats/measure.h"
2628
#include "opencensus/stats/measure_descriptor.h"
2729
#include "opencensus/stats/measure_registry.h"
@@ -35,7 +37,7 @@ namespace stats {
3537
class MockExporter : public StatsExporter::Handler {
3638
public:
3739
static void Register(absl::Span<const ViewDescriptor> expected_descriptors) {
38-
opencensus::stats::StatsExporter::RegisterHandler(
40+
opencensus::stats::StatsExporter::RegisterPushHandler(
3941
absl::make_unique<MockExporter>(expected_descriptors));
4042
}
4143

@@ -81,8 +83,6 @@ class StatsExporterTest : public ::testing::Test {
8183
descriptor2_.set_measure(kMeasureId);
8284
descriptor2_.set_aggregation(
8385
Aggregation::Distribution(BucketBoundaries::Explicit({0})));
84-
SetAggregationWindow(AggregationWindow::Interval(absl::Hours(1)),
85-
&descriptor2_);
8686
}
8787

8888
void TearDown() {
@@ -102,6 +102,9 @@ TEST_F(StatsExporterTest, AddView) {
102102
MockExporter::Register({descriptor1_, descriptor2_});
103103
StatsExporter::AddView(descriptor1_);
104104
StatsExporter::AddView(descriptor2_);
105+
EXPECT_THAT(StatsExporter::GetViewData(),
106+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_),
107+
::testing::Key(descriptor2_)));
105108
Export();
106109
}
107110

@@ -110,6 +113,10 @@ TEST_F(StatsExporterTest, UpdateView) {
110113
StatsExporter::AddView(descriptor1_);
111114
StatsExporter::AddView(descriptor2_);
112115
StatsExporter::AddView(descriptor1_edited_);
116+
EXPECT_THAT(
117+
StatsExporter::GetViewData(),
118+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_edited_),
119+
::testing::Key(descriptor2_)));
113120
Export();
114121
}
115122

@@ -118,6 +125,8 @@ TEST_F(StatsExporterTest, RemoveView) {
118125
StatsExporter::AddView(descriptor1_);
119126
StatsExporter::AddView(descriptor2_);
120127
StatsExporter::RemoveView(descriptor1_.name());
128+
EXPECT_THAT(StatsExporter::GetViewData(),
129+
::testing::UnorderedElementsAre(::testing::Key(descriptor2_)));
121130
Export();
122131
}
123132

@@ -128,6 +137,16 @@ TEST_F(StatsExporterTest, MultipleExporters) {
128137
Export();
129138
}
130139

140+
TEST_F(StatsExporterTest, IntervalViewRejected) {
141+
MockExporter::Register({});
142+
ViewDescriptor interval_descriptor = ViewDescriptor().set_name("interval");
143+
SetAggregationWindow(AggregationWindow::Interval(absl::Hours(1)),
144+
&interval_descriptor);
145+
StatsExporter::AddView(interval_descriptor);
146+
EXPECT_TRUE(StatsExporter::GetViewData().empty());
147+
Export();
148+
}
149+
131150
TEST_F(StatsExporterTest, TimedExport) {
132151
MockExporter::Register({descriptor1_});
133152
StatsExporter::AddView(descriptor1_);

opencensus/stats/stats_exporter.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <functional>
2020
#include <memory>
2121
#include <unordered_map>
22+
#include <utility>
23+
#include <vector>
2224

2325
#include "absl/strings/string_view.h"
2426
#include "opencensus/stats/view.h"
@@ -32,24 +34,29 @@ namespace stats {
3234
// StatsExporter is thread-safe.
3335
class StatsExporter final {
3436
public:
35-
// Inserts a new view, replacing any existing view with the same name.
37+
// Inserts a new view, replacing any existing view with the same name. Only
38+
// Cumulative views are supported.
3639
static void AddView(const ViewDescriptor& view);
3740
// Removes the view with 'name' from the registry, if one is registered.
3841
static void RemoveView(absl::string_view name);
3942

40-
// StatsExporter::Handler is the interface for exporters that export recorded
41-
// data for registered views. The exporter should provide a static Register()
42-
// method that takes any arguments needed by the exporter (e.g. a URL to
43-
// export to) and calls StatsExporter::RegisterHandler itself.
43+
// StatsExporter::Handler is the interface for push exporters that export
44+
// recorded data for registered views. The exporter should provide a static
45+
// Register() method that takes any arguments needed by the exporter (e.g. a
46+
// URL to export to) and calls StatsExporter::RegisterHandler itself.
4447
class Handler {
4548
public:
4649
virtual ~Handler() = default;
4750
virtual void ExportViewData(const ViewDescriptor& descriptor,
4851
const ViewData& data) = 0;
4952
};
5053

51-
// This should only be called by Handler's Register() methods.
52-
static void RegisterHandler(std::unique_ptr<Handler> handler);
54+
// This should only be called by push exporters' Register() methods.
55+
static void RegisterPushHandler(std::unique_ptr<Handler> handler);
56+
57+
// Retrieves current data for all registered views, for implementing pull
58+
// exporters.
59+
static std::vector<std::pair<ViewDescriptor, ViewData>> GetViewData();
5360

5461
private:
5562
friend class StatsExporterTest;

0 commit comments

Comments
 (0)