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

Commit 36261e2

Browse files
Ian Sturdyg-easy
authored andcommitted
Change the stats exporter interface to batch all views together. (#76)
This allows the Stackdriver exporter to batch TimeSeries from different views into fewer RPCs.
1 parent ed08da1 commit 36261e2

File tree

7 files changed

+109
-79
lines changed

7 files changed

+109
-79
lines changed

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ class StackdriverExporter::Handler
4040
public:
4141
Handler(absl::string_view project_id, absl::string_view opencensus_task);
4242

43-
void ExportViewData(const opencensus::stats::ViewDescriptor& descriptor,
44-
const opencensus::stats::ViewData& data)
43+
void ExportViewData(
44+
const std::vector<std::pair<opencensus::stats::ViewDescriptor,
45+
opencensus::stats::ViewData>>& data)
4546
LOCKS_EXCLUDED(mu_) override;
4647

4748
private:
@@ -70,20 +71,26 @@ StackdriverExporter::Handler::Handler(absl::string_view project_id,
7071
::grpc::GoogleDefaultCredentials()))) {}
7172

7273
void StackdriverExporter::Handler::ExportViewData(
73-
const opencensus::stats::ViewDescriptor& descriptor,
74-
const opencensus::stats::ViewData& data) {
74+
const std::vector<std::pair<opencensus::stats::ViewDescriptor,
75+
opencensus::stats::ViewData>>& data) {
76+
// TODO: refactor to avoid copying the timeseries.
7577
absl::MutexLock l(&mu_);
76-
if (!MaybeRegisterView(descriptor)) {
77-
return;
78+
std::vector<google::monitoring::v3::TimeSeries> time_series;
79+
for (const auto& datum : data) {
80+
if (!MaybeRegisterView(datum.first)) {
81+
continue;
82+
}
83+
const auto view_time_series =
84+
MakeTimeSeries(datum.first, datum.second, opencensus_task_);
85+
time_series.insert(time_series.end(), view_time_series.begin(),
86+
view_time_series.end());
7887
}
7988

8089
// TODO: use asynchronous RPCs.
81-
const auto time_series = MakeTimeSeries(descriptor, data, opencensus_task_);
8290
int i = 0;
8391
while (i < time_series.size()) {
8492
auto request = google::monitoring::v3::CreateTimeSeriesRequest();
8593
request.set_name(project_id_);
86-
// TODO: refactor to avoid copying each timeseries.
8794
for (int batch_index = 0; batch_index < kTimeSeriesBatchSize;
8895
++batch_index) {
8996
*request.add_time_series() = time_series[i];

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ std::string DataToString(const opencensus::stats::Distribution& data) {
5050
class StdoutExporter::Handler
5151
: public opencensus::stats::StatsExporter::Handler {
5252
public:
53-
void ExportViewData(const opencensus::stats::ViewDescriptor& descriptor,
54-
const opencensus::stats::ViewData& data) override;
53+
void ExportViewData(
54+
const std::vector<std::pair<opencensus::stats::ViewDescriptor,
55+
opencensus::stats::ViewData>>& data) override;
5556

5657
private:
5758
// Implements ExportViewData for supported data types.
@@ -69,21 +70,24 @@ void StdoutExporter::Register() {
6970
}
7071

7172
void StdoutExporter::Handler::ExportViewData(
72-
const opencensus::stats::ViewDescriptor& descriptor,
73-
const opencensus::stats::ViewData& data) {
74-
switch (data.type()) {
75-
case opencensus::stats::ViewData::Type::kDouble:
76-
ExportViewDataImpl(descriptor, data.start_time(), data.end_time(),
77-
data.double_data());
78-
break;
79-
case opencensus::stats::ViewData::Type::kInt64:
80-
ExportViewDataImpl(descriptor, data.start_time(), data.end_time(),
81-
data.int_data());
82-
break;
83-
case opencensus::stats::ViewData::Type::kDistribution:
84-
ExportViewDataImpl(descriptor, data.start_time(), data.end_time(),
85-
data.distribution_data());
86-
break;
73+
const std::vector<std::pair<opencensus::stats::ViewDescriptor,
74+
opencensus::stats::ViewData>>& data) {
75+
for (const auto& datum : data) {
76+
const auto& view_data = datum.second;
77+
switch (view_data.type()) {
78+
case opencensus::stats::ViewData::Type::kDouble:
79+
ExportViewDataImpl(datum.first, view_data.start_time(),
80+
view_data.end_time(), view_data.double_data());
81+
break;
82+
case opencensus::stats::ViewData::Type::kInt64:
83+
ExportViewDataImpl(datum.first, view_data.start_time(),
84+
view_data.end_time(), view_data.int_data());
85+
break;
86+
case opencensus::stats::ViewData::Type::kDistribution:
87+
ExportViewDataImpl(datum.first, view_data.start_time(),
88+
view_data.end_time(), view_data.distribution_data());
89+
break;
90+
}
8791
}
8892
}
8993

opencensus/stats/examples/exporter_example.cc

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,30 @@ class ExampleExporter : public opencensus::stats::StatsExporter::Handler {
4242
absl::make_unique<ExampleExporter>());
4343
}
4444

45-
void ExportViewData(const opencensus::stats::ViewDescriptor& descriptor,
46-
const opencensus::stats::ViewData& data) override {
47-
if (data.type() != opencensus::stats::ViewData::Type::kDouble) {
48-
// This example only supports double data (i.e. Sum() aggregation).
49-
return;
50-
}
51-
std::string output;
52-
absl::StrAppend(&output, "\nData for view \"", descriptor.name(),
53-
"\" from ", absl::FormatTime(data.start_time()), " to ",
54-
absl::FormatTime(data.end_time()), ":\n");
55-
for (const auto& row : data.double_data()) {
56-
for (int i = 0; i < descriptor.columns().size(); ++i) {
57-
absl::StrAppend(&output, descriptor.columns()[i], ":", row.first[i],
58-
", ");
45+
void ExportViewData(
46+
const std::vector<std::pair<opencensus::stats::ViewDescriptor,
47+
opencensus::stats::ViewData>>& data)
48+
override {
49+
for (const auto& datum : data) {
50+
const auto& descriptor = datum.first;
51+
const auto& view_data = datum.second;
52+
if (view_data.type() != opencensus::stats::ViewData::Type::kDouble) {
53+
// This example only supports double data (i.e. Sum() aggregation).
54+
return;
55+
}
56+
std::string output;
57+
absl::StrAppend(&output, "\nData for view \"", descriptor.name(),
58+
"\" from ", absl::FormatTime(view_data.start_time()),
59+
" to ", absl::FormatTime(view_data.end_time()), ":\n");
60+
for (const auto& row : view_data.double_data()) {
61+
for (int i = 0; i < descriptor.columns().size(); ++i) {
62+
absl::StrAppend(&output, descriptor.columns()[i], ":", row.first[i],
63+
", ");
64+
}
65+
absl::StrAppend(&output, row.second, "\n");
5966
}
60-
absl::StrAppend(&output, row.second, "\n");
67+
std::cout << output;
6168
}
62-
std::cout << output;
6369
}
6470
};
6571

opencensus/stats/internal/stats_exporter.cc

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,13 @@ StatsExporterImpl::GetViewData() {
6969

7070
void StatsExporterImpl::Export() {
7171
absl::ReaderMutexLock l(&mu_);
72+
std::vector<std::pair<ViewDescriptor, ViewData>> data;
73+
data.reserve(views_.size());
7274
for (const auto& view : views_) {
73-
SendToHandlers(view.second->descriptor(), view.second->GetData());
75+
data.emplace_back(view.second->descriptor(), view.second->GetData());
76+
}
77+
for (auto& handler : handlers_) {
78+
handler->ExportViewData(data);
7479
}
7580
}
7681

@@ -79,14 +84,6 @@ void StatsExporterImpl::ClearHandlersForTesting() {
7984
handlers_.clear();
8085
}
8186

82-
void StatsExporterImpl::SendToHandlers(const ViewDescriptor& descriptor,
83-
const ViewData& data)
84-
SHARED_LOCKS_REQUIRED(mu_) {
85-
for (auto& handler : handlers_) {
86-
handler->ExportViewData(descriptor, data);
87-
}
88-
}
89-
9087
void StatsExporterImpl::StartExportThread() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
9188
t_ = std::thread(&StatsExporterImpl::RunWorkerLoop, this);
9289
thread_started_ = true;

opencensus/stats/internal/stats_exporter_impl.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ class StatsExporterImpl {
4949
private:
5050
StatsExporterImpl() {}
5151

52-
void SendToHandlers(const ViewDescriptor& descriptor, const ViewData& data)
53-
SHARED_LOCKS_REQUIRED(mu_);
54-
5552
void StartExportThread() EXCLUSIVE_LOCKS_REQUIRED(mu_);
5653

5754
// Loops forever, calling Export() every export_interval_.

opencensus/stats/internal/stats_exporter_test.cc

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,29 @@
3232
namespace opencensus {
3333
namespace stats {
3434

35-
// A mock exporter that checks whether it is called with the right set of view
36-
// descriptors.
35+
// A mock exporter that assigns exported data to the provided pointer.
3736
class MockExporter : public StatsExporter::Handler {
3837
public:
39-
static void Register(absl::Span<const ViewDescriptor> expected_descriptors) {
38+
static void Register(
39+
std::vector<std::pair<ViewDescriptor, ViewData>>* output) {
4040
opencensus::stats::StatsExporter::RegisterPushHandler(
41-
absl::make_unique<MockExporter>(expected_descriptors));
41+
absl::make_unique<MockExporter>(output));
4242
}
4343

44-
MockExporter(absl::Span<const ViewDescriptor> expected_descriptors)
45-
: expected_descriptors_(expected_descriptors.begin(),
46-
expected_descriptors.end()) {}
44+
MockExporter(std::vector<std::pair<ViewDescriptor, ViewData>>* output)
45+
: output_(output) {}
4746

48-
~MockExporter() {
49-
EXPECT_THAT(actual_descriptors_,
50-
::testing::UnorderedElementsAreArray(expected_descriptors_));
51-
}
52-
53-
void ExportViewData(const ViewDescriptor& descriptor,
54-
const ViewData& data) override {
55-
actual_descriptors_.push_back(descriptor);
47+
void ExportViewData(
48+
const std::vector<std::pair<ViewDescriptor, ViewData>>& data) override {
49+
// Looping because ViewData is (intentionally) copy-constructable but not
50+
// copy_assignable.
51+
for (const auto& datum : data) {
52+
output_->emplace_back(datum.first, datum.second);
53+
}
5654
}
5755

5856
private:
59-
const std::vector<ViewDescriptor> expected_descriptors_;
60-
std::vector<ViewDescriptor> actual_descriptors_;
57+
std::vector<std::pair<ViewDescriptor, ViewData>>* output_;
6158
};
6259

6360
constexpr char kMeasureId[] = "test_measure_id";
@@ -99,17 +96,22 @@ class StatsExporterTest : public ::testing::Test {
9996
};
10097

10198
TEST_F(StatsExporterTest, AddView) {
102-
MockExporter::Register({descriptor1_, descriptor2_});
99+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data;
100+
MockExporter::Register(&exported_data);
103101
descriptor1_.RegisterForExport();
104102
descriptor2_.RegisterForExport();
105103
EXPECT_THAT(StatsExporter::GetViewData(),
106104
::testing::UnorderedElementsAre(::testing::Key(descriptor1_),
107105
::testing::Key(descriptor2_)));
108106
Export();
107+
EXPECT_THAT(exported_data,
108+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_),
109+
::testing::Key(descriptor2_)));
109110
}
110111

111112
TEST_F(StatsExporterTest, UpdateView) {
112-
MockExporter::Register({descriptor1_edited_, descriptor2_});
113+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data;
114+
MockExporter::Register(&exported_data);
113115
descriptor1_.RegisterForExport();
114116
descriptor2_.RegisterForExport();
115117
descriptor1_edited_.RegisterForExport();
@@ -118,39 +120,56 @@ TEST_F(StatsExporterTest, UpdateView) {
118120
::testing::UnorderedElementsAre(::testing::Key(descriptor1_edited_),
119121
::testing::Key(descriptor2_)));
120122
Export();
123+
EXPECT_THAT(exported_data, ::testing::UnorderedElementsAre(
124+
::testing::Key(descriptor1_edited_),
125+
::testing::Key(descriptor2_)));
121126
}
122127

123128
TEST_F(StatsExporterTest, RemoveView) {
124-
MockExporter::Register({descriptor2_});
129+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data;
130+
MockExporter::Register(&exported_data);
125131
descriptor1_.RegisterForExport();
126132
descriptor2_.RegisterForExport();
127133
StatsExporter::RemoveView(descriptor1_.name());
128134
EXPECT_THAT(StatsExporter::GetViewData(),
129135
::testing::UnorderedElementsAre(::testing::Key(descriptor2_)));
130136
Export();
137+
EXPECT_THAT(exported_data,
138+
::testing::UnorderedElementsAre(::testing::Key(descriptor2_)));
131139
}
132140

133141
TEST_F(StatsExporterTest, MultipleExporters) {
134-
MockExporter::Register({descriptor1_});
135-
MockExporter::Register({descriptor1_});
142+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data_1;
143+
MockExporter::Register(&exported_data_1);
144+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data_2;
145+
MockExporter::Register(&exported_data_2);
136146
descriptor1_.RegisterForExport();
137147
Export();
148+
EXPECT_THAT(exported_data_1,
149+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_)));
150+
EXPECT_THAT(exported_data_2,
151+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_)));
138152
}
139153

140154
TEST_F(StatsExporterTest, IntervalViewRejected) {
141-
MockExporter::Register({});
155+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data;
156+
MockExporter::Register(&exported_data);
142157
ViewDescriptor interval_descriptor = ViewDescriptor().set_name("interval");
143158
SetAggregationWindow(AggregationWindow::Interval(absl::Hours(1)),
144159
&interval_descriptor);
145160
interval_descriptor.RegisterForExport();
146161
EXPECT_TRUE(StatsExporter::GetViewData().empty());
147162
Export();
163+
EXPECT_TRUE(exported_data.empty());
148164
}
149165

150166
TEST_F(StatsExporterTest, TimedExport) {
151-
MockExporter::Register({descriptor1_});
167+
std::vector<std::pair<ViewDescriptor, ViewData>> exported_data;
168+
MockExporter::Register(&exported_data);
152169
descriptor1_.RegisterForExport();
153170
absl::SleepFor(absl::Seconds(11));
171+
EXPECT_THAT(exported_data,
172+
::testing::UnorderedElementsAre(::testing::Key(descriptor1_)));
154173
}
155174

156175
} // namespace stats

opencensus/stats/stats_exporter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class StatsExporter final {
4545
class Handler {
4646
public:
4747
virtual ~Handler() = default;
48-
virtual void ExportViewData(const ViewDescriptor& descriptor,
49-
const ViewData& data) = 0;
48+
virtual void ExportViewData(
49+
const std::vector<std::pair<ViewDescriptor, ViewData>>& data) = 0;
5050
};
5151

5252
// This should only be called by push exporters' Register() methods.

0 commit comments

Comments
 (0)