Skip to content

Commit

Permalink
Add OStream metrics exporter (open-telemetry#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
HudsonHumphries authored Aug 4, 2020
1 parent 318f37a commit 6631930
Show file tree
Hide file tree
Showing 6 changed files with 591 additions and 0 deletions.
23 changes: 23 additions & 0 deletions exporters/ostream/BUILD
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
package(default_visibility = ["//visibility:public"])

cc_library(
name = "ostream_metrics_exporter",
srcs = [
"src/metrics_exporter.cc",
],
hdrs = [
"include/opentelemetry/exporters/ostream/metrics_exporter.h",
],
strip_include_prefix = "include",
deps = [
"//sdk/src/metrics",
],
)

cc_test(
name = "ostream_metrics_test",
srcs = ["test/ostream_metrics_test.cc"],
deps = [
":ostream_metrics_exporter",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "ostream_span_exporter",
srcs = [
Expand Down
10 changes: 10 additions & 0 deletions exporters/ostream/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
include_directories(include)

add_library(opentelemetry_exporter_ostream_metrics src/metrics_exporter.cc)
add_library(opentelemetry_exporter_ostream_span src/span_exporter.cc)

add_executable(ostream_metrics_test test/ostream_metrics_test.cc)
add_executable(ostream_span_test test/ostream_span_test.cc)

target_link_libraries(
ostream_span_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
opentelemetry_exporter_ostream_span)

target_link_libraries(
ostream_metrics_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
opentelemetry_exporter_ostream_metrics)

gtest_add_tests(TARGET ostream_metrics_test TEST_PREFIX exporter. TEST_LIST
ostream_metrics_test)
gtest_add_tests(TARGET ostream_span_test TEST_PREFIX exporter. TEST_LIST
ostream_span_test)
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#pragma once

#include <iostream>
#include "opentelemetry/sdk/metrics/aggregator/exact_aggregator.h"
#include "opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h"
#include "opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h"
#include "opentelemetry/sdk/metrics/exporter.h"
#include "opentelemetry/sdk/metrics/record.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdkmetrics = opentelemetry::sdk::metrics;

namespace exporter
{
namespace metrics
{

/**
* The OStreamMetricsExporter exports record data through an ostream
*/
class OStreamMetricsExporter final : public sdkmetrics::MetricsExporter
{
public:
/**
* Create an OStreamMetricsExporter. This constructor takes in a reference to an ostream that the
* export() function will send span data into.
* The default ostream is set to stdout
*/
explicit OStreamMetricsExporter(std::ostream &sout = std::cout) noexcept;

sdkmetrics::ExportResult Export(const std::vector<sdkmetrics::Record> &records) noexcept override;

private:
std::ostream &sout_;

/**
* Send specific data from the given AggregatorVariant based on what AggregatorKind
* it is holding. Each Aggregator holds data differently, so each have their own
* custom printing.
*/
template <typename T>
void PrintAggregatorVariant(sdkmetrics::AggregatorVariant value)
{
auto agg = nostd::get<std::shared_ptr<sdkmetrics::Aggregator<T>>>(value);
auto aggKind = agg->get_aggregator_kind();

if (!agg)
return;
switch (aggKind)
{
case sdkmetrics::AggregatorKind::Counter:
{
sout_ << "\n sum : " << agg->get_checkpoint()[0];
}
break;
case sdkmetrics::AggregatorKind::MinMaxSumCount:
{
auto mmsc = agg->get_checkpoint();
sout_ << "\n min : " << mmsc[0] << "\n max : " << mmsc[1]
<< "\n sum : " << mmsc[2] << "\n count : " << mmsc[3];
}
break;
case sdkmetrics::AggregatorKind::Gauge:
{
auto timestamp = agg->get_checkpoint_timestamp();

sout_ << "\n last value : " << agg->get_checkpoint()[0]
<< "\n timestamp : " << std::to_string(timestamp.time_since_epoch().count());
}
break;
case sdkmetrics::AggregatorKind::Exact:
{
// TODO: Find better way to print quantiles
if (agg->get_quant_estimation())
{
sout_ << "\n quantiles : "
<< "[0: " << agg->get_quantiles(0) << ", "
<< ".25: " << agg->get_quantiles(.25) << ", "
<< ".50: " << agg->get_quantiles(.50) << ", "
<< ".75: " << agg->get_quantiles(.75) << ", "
<< "1: " << agg->get_quantiles(1) << ']';
}
else
{
auto vec = agg->get_checkpoint();
int size = vec.size();
int i = 1;

sout_ << "\n values : " << '[';

for (auto val : vec)
{
sout_ << val;
if (i != size)
sout_ << ", ";
i++;
}
sout_ << ']';
}
}
break;
case sdkmetrics::AggregatorKind::Histogram:
{
auto boundaries = agg->get_boundaries();
auto counts = agg->get_counts();

int boundaries_size = boundaries.size();
int counts_size = counts.size();

sout_ << "\n buckets : " << '[';

for (int i = 0; i < boundaries_size; i++)
{
sout_ << boundaries[i];

if (i != boundaries_size - 1)
sout_ << ", ";
}
sout_ << ']';

sout_ << "\n counts : " << '[';
for (int i = 0; i < counts_size; i++)
{
sout_ << counts[i];

if (i != counts_size - 1)
sout_ << ", ";
}
sout_ << ']';
}
break;
case sdkmetrics::AggregatorKind::Sketch:
{
auto boundaries = agg->get_boundaries();
auto counts = agg->get_counts();

int boundaries_size = boundaries.size();
int counts_size = counts.size();

sout_ << "\n buckets : " << '[';

for (int i = 0; i < boundaries_size; i++)
{
sout_ << boundaries[i];

if (i != boundaries_size - 1)
sout_ << ", ";
}
sout_ << ']';

sout_ << "\n counts : " << '[';
for (int i = 0; i < counts_size; i++)
{
sout_ << counts[i];

if (i != counts_size - 1)
sout_ << ", ";
}
sout_ << ']';
}
break;
}
}
};
} // namespace metrics
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
50 changes: 50 additions & 0 deletions exporters/ostream/src/metrics_exporter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "opentelemetry/exporters/ostream/metrics_exporter.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace metrics
{

OStreamMetricsExporter::OStreamMetricsExporter(std::ostream &sout) noexcept : sout_(sout) {}

sdkmetrics::ExportResult OStreamMetricsExporter::Export(
const std::vector<sdk::metrics::Record> &records) noexcept
{
for (auto record : records)
{
sout_ << "{"
<< "\n name : " << record.GetName()
<< "\n description : " << record.GetDescription()
<< "\n labels : " << record.GetLabels();

auto aggregator = record.GetAggregator();

/**
* Unpack the AggregatorVariant from the record so we can pass the data type to
* PrintAggregatorVariant to unpack the Aggregator from the variant.
*/
if (nostd::holds_alternative<std::shared_ptr<sdkmetrics::Aggregator<int>>>(aggregator))
{
PrintAggregatorVariant<int>(aggregator);
}
else if (nostd::holds_alternative<std::shared_ptr<sdkmetrics::Aggregator<short>>>(aggregator))
{
PrintAggregatorVariant<short>(aggregator);
}
else if (nostd::holds_alternative<std::shared_ptr<sdkmetrics::Aggregator<double>>>(aggregator))
{
PrintAggregatorVariant<double>(aggregator);
}
else if (nostd::holds_alternative<std::shared_ptr<sdkmetrics::Aggregator<float>>>(aggregator))
{
PrintAggregatorVariant<float>(aggregator);
}
sout_ << "\n}\n";
}
return sdkmetrics::ExportResult::kSuccess;
}

} // namespace metrics
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
Loading

0 comments on commit 6631930

Please sign in to comment.