Skip to content

Commit

Permalink
Ostream metric exporter (#1196)
Browse files Browse the repository at this point in the history
  • Loading branch information
esigo authored Feb 19, 2022
1 parent 3508d7c commit 9502339
Show file tree
Hide file tree
Showing 7 changed files with 476 additions and 9 deletions.
33 changes: 32 additions & 1 deletion exporters/ostream/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,39 @@ cc_library(
],
)

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

cc_test(
name = "ostream_metric_test",
srcs = ["test/ostream_metric_test.cc"],
tags = [
"ostream",
"test",
],
deps = [
":ostream_metric_exporter",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "ostream_metrics_test",
name = "ostream_metrics_test_deprecated",
srcs = ["test/ostream_metrics_test.cc"],
tags = [
"ostream",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once
#ifndef ENABLE_METRICS_PREVIEW

# include <iostream>
# include <string>
# include "opentelemetry/common/spin_lock_mutex.h"
# include "opentelemetry/nostd/span.h"
# include "opentelemetry/sdk/metrics/instruments.h"
# include "opentelemetry/sdk/metrics/metric_exporter.h"
# include "opentelemetry/sdk/metrics/recordable.h"
# include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace metrics
{

/**
* The OStreamMetricExporter exports record data through an ostream
*/
class OStreamMetricExporter final : public opentelemetry::sdk::metrics::MetricExporter
{
public:
/**
* Create an OStreamMetricExporter. 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 OStreamMetricExporter(std::ostream &sout = std::cout) noexcept;

/**
* Export
* @param records a span of unique pointers to metrics data
*/
sdk::common::ExportResult Export(
const nostd::span<std::unique_ptr<opentelemetry::sdk::metrics::MetricData>> &records) noexcept
override;

/**
* Force flush the exporter.
*/
bool ForceFlush(
std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override;

/**
* Shut down the exporter.
* @param timeout an optional timeout, the default timeout of 0 means that no
* timeout is applied.
* @return return the status of this operation
*/
bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override;

private:
std::ostream &sout_;
bool is_shutdown_ = false;
mutable opentelemetry::common::SpinLockMutex lock_;
bool isShutdown() const noexcept;
void printPointData(opentelemetry::sdk::metrics::PointType &point_data);
};
} // namespace metrics
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif
150 changes: 150 additions & 0 deletions exporters/ostream/src/metric_exporter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#ifndef ENABLE_METRICS_PREVIEW
# include "opentelemetry/exporters/ostream/metric_exporter.h"
# include <algorithm>
# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
# include "opentelemetry/sdk_config.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace metrics
{

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

sdk::common::ExportResult OStreamMetricExporter::Export(
const nostd::span<std::unique_ptr<opentelemetry::sdk::metrics::MetricData>> &records) noexcept
{
if (isShutdown())
{
OTEL_INTERNAL_LOG_ERROR("[OStream Metric] Exporting "
<< records.size() << " records(s) failed, exporter is shutdown");
return sdk::common::ExportResult::kFailure;
}

for (auto &record : records)
{
sout_ << "{"
<< "\n name : " << record->instrumentation_library_->GetName()
<< "\n version : " << record->instrumentation_library_->GetVersion();
printPointData(record->point_data_);
sout_ << "\n}\n";
}
return sdk::common::ExportResult::kSuccess;
}

template <typename T>
inline void printVec(std::ostream &os, std::vector<T> &vec)
{
os << '[';
if (vec.size() > 1)
{
std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<T>(os, ", "));
}
if (!vec.empty())
{
os << vec.back();
}
os << ']';
}

void OStreamMetricExporter::printPointData(opentelemetry::sdk::metrics::PointType &point_data)
{
if (nostd::holds_alternative<sdk::metrics::SumPointData>(point_data))
{
auto sum_point_data = nostd::get<sdk::metrics::SumPointData>(point_data);
sout_ << "\n type : SumPointData";
sout_ << "\n start timestamp : "
<< std::to_string(sum_point_data.start_epoch_nanos_.time_since_epoch().count());
sout_ << "\n end timestamp : "
<< std::to_string(sum_point_data.end_epoch_nanos_.time_since_epoch().count());
sout_ << "\n value : ";
if (nostd::holds_alternative<double>(sum_point_data.value_))
{
sout_ << nostd::get<double>(sum_point_data.value_);
}
else if (nostd::holds_alternative<long>(sum_point_data.value_))
{
sout_ << nostd::get<long>(sum_point_data.value_);
}
}
else if (nostd::holds_alternative<sdk::metrics::HistogramPointData>(point_data))
{
auto histogram_point_data = nostd::get<sdk::metrics::HistogramPointData>(point_data);
sout_ << "\n type : HistogramPointData";
sout_ << "\n timestamp : "
<< std::to_string(histogram_point_data.epoch_nanos_.time_since_epoch().count());
sout_ << "\n count : " << histogram_point_data.count_;
sout_ << "\n sum : ";
if (nostd::holds_alternative<double>(histogram_point_data.sum_))
{
sout_ << nostd::get<double>(histogram_point_data.sum_);
}
else if (nostd::holds_alternative<long>(histogram_point_data.sum_))
{
sout_ << nostd::get<long>(histogram_point_data.sum_);
}

sout_ << "\n buckets : ";
if (nostd::holds_alternative<std::vector<double>>(histogram_point_data.boundaries_))
{
auto &double_boundaries = nostd::get<std::vector<double>>(histogram_point_data.boundaries_);
printVec(sout_, double_boundaries);
}
else if (nostd::holds_alternative<std::vector<long>>(histogram_point_data.boundaries_))
{
auto &long_boundaries = nostd::get<std::vector<long>>(histogram_point_data.boundaries_);
printVec(sout_, long_boundaries);
}

sout_ << "\n counts : ";
printVec(sout_, histogram_point_data.counts_);
}
else if (nostd::holds_alternative<sdk::metrics::LastValuePointData>(point_data))
{
auto last_point_data = nostd::get<sdk::metrics::LastValuePointData>(point_data);
sout_ << "\n type : LastValuePointData";
sout_ << "\n timestamp : "
<< std::to_string(last_point_data.epoch_nanos_.time_since_epoch().count())
<< std::boolalpha << "\n valid : " << last_point_data.is_lastvalue_valid_;
sout_ << "\n value : ";
if (nostd::holds_alternative<double>(last_point_data.value_))
{
sout_ << nostd::get<double>(last_point_data.value_);
}
else if (nostd::holds_alternative<long>(last_point_data.value_))
{
sout_ << nostd::get<long>(last_point_data.value_);
}
}
else if (nostd::holds_alternative<sdk::metrics::DropPointData>(point_data))
{}
}

bool OStreamMetricExporter::ForceFlush(std::chrono::microseconds timeout) noexcept
{
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
return true;
}

bool OStreamMetricExporter::Shutdown(std::chrono::microseconds timeout) noexcept
{
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
is_shutdown_ = true;
return true;
}

bool OStreamMetricExporter::isShutdown() const noexcept
{
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
return is_shutdown_;
}

} // namespace metrics
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif
Loading

1 comment on commit 9502339

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'OpenTelemetry-cpp sdk Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: 9502339 Previous: 3508d7c Ratio
BM_LockFreeBuffer/2 3302293.062210083 ns/iter 1271984.1003417969 ns/iter 2.60

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.