Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ostream metrics example #1312

Merged
merged 12 commits into from
Apr 12, 2022
15 changes: 15 additions & 0 deletions examples/metrics_simple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ cc_binary(
"//sdk/src/_metrics:metrics_deprecated",
],
)

# TODO - Uncomment once MetricData interface is finalised
# cc_binary(
# name = "metrics_ostream_example",
# srcs = [
# "metrics_ostream.cc",
# ],
# linkopts = ["-pthread"],
# tags = ["ostream"],
# deps = [
# "//api",
# "//exporters/ostream:ostream_metric_exporter",
# "//sdk/src/metrics",
# ],
# )
68 changes: 68 additions & 0 deletions examples/metrics_simple/metrics_ostream.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include <memory>
#ifndef ENABLE_METRICS_PREVIEW
# include <chrono>
# include <thread>
# include "opentelemetry/exporters/ostream/metric_exporter.h"
# include "opentelemetry/metrics/provider.h"
# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h"
# include "opentelemetry/sdk/metrics/meter.h"
# include "opentelemetry/sdk/metrics/meter_provider.h"

# include <iostream>

namespace metric_sdk = opentelemetry::sdk::metrics;
namespace nostd = opentelemetry::nostd;
namespace common = opentelemetry::common;
namespace exportermetrics = opentelemetry::exporter::metrics;
namespace metrics_api = opentelemetry::metrics;

void sync_sum()
{
std::unique_ptr<metric_sdk::MetricExporter> exporter{new exportermetrics::OStreamMetricExporter};
std::vector<std::unique_ptr<metric_sdk::MetricExporter>> exporters;

std::string name{"ostream_metric_example"};
std::string version{"1.2.0"};
std::string schema{"ostream_metric_example"};

// Initialize and set the global MeterProvider
metric_sdk::PeriodicExportingMetricReaderOptions options;
options.export_interval_millis = std::chrono::milliseconds(1000);
options.export_timeout_millis = std::chrono::milliseconds(500);
std::unique_ptr<metric_sdk::MetricReader> reader{
new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options)};
auto provider = std::shared_ptr<metrics_api::MeterProvider>(
new metric_sdk::MeterProvider(std::move(exporters)));
auto p = std::static_pointer_cast<metric_sdk::MeterProvider>(provider);
p->AddMetricReader(std::move(reader));
std::unique_ptr<metric_sdk::InstrumentSelector> instrument_selector{
new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kCounter, name)};
std::unique_ptr<metric_sdk::MeterSelector> meter_selector{
new metric_sdk::MeterSelector(name, version, schema)};
std::unique_ptr<metric_sdk::View> view{
new metric_sdk::View{name, "description", metric_sdk::AggregationType::kSum}};
p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view));
metrics_api::Provider::SetMeterProvider(provider);

// Get the Meter from the MeterProvider
nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0");
auto double_counter = meter->CreateDoubleCounter(name);
double_counter->Add(28.5);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
double_counter->Add(3.14);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
double_counter->Add(23.5);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
Copy link
Member

Choose a reason for hiding this comment

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

nit - should we add small metrics instrumentation under (example/common) similar to how we do for traces and logs?

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks, added.

p->ForceFlush();
}

int main()
{
sync_sum();
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ class OStreamMetricExporter final : public opentelemetry::sdk::metrics::MetricEx

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

/**
* Force flush the exporter.
Expand All @@ -60,7 +58,7 @@ class OStreamMetricExporter final : public opentelemetry::sdk::metrics::MetricEx
bool is_shutdown_ = false;
mutable opentelemetry::common::SpinLockMutex lock_;
bool isShutdown() const noexcept;
void printPointData(opentelemetry::sdk::metrics::PointType &point_data);
void printPointData(const opentelemetry::sdk::metrics::PointType &point_data);
};
} // namespace metrics
} // namespace exporter
Expand Down
60 changes: 25 additions & 35 deletions exporters/ostream/src/metric_exporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,46 @@ namespace exporter
namespace metrics
{

template <typename Container>
inline void printVec(std::ostream &os, Container &vec)
{
using T = typename std::decay<decltype(*vec.begin())>::type;
os << '[';
if (vec.size() > 1)
{
std::copy(vec.begin(), vec.end(), std::ostream_iterator<T>(os, ", "));
}
os << ']';
}

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
const sdk::metrics::MetricData &data) noexcept
Copy link
Member

Choose a reason for hiding this comment

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

This may need further changes, based on the review for #1299, as it adds Resources and Instrumentation Info to Metric Data to be exported.

Copy link
Member

Choose a reason for hiding this comment

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

#1299 is merged. you can modify the PR to use ResourceMetrics instead of MetricData.

Copy link
Member

@lalitb lalitb Apr 8, 2022

Choose a reason for hiding this comment

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

@esigo - Just want to check if you want this to be reviewed now, as I was thinking to review it once it incorporates changes for ResourceMetrics as mentioned above :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Hi @lalitb, I'm rewriting the unit tests, should be done by tomorrow. I'll ping you when I'm done.
Thanks

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, @esigo. Just wanted to ensure that I am not delaying the review comments in case you are expecting it to be reviewed :)

Copy link
Member Author

Choose a reason for hiding this comment

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

@lalitb this should be ready for review, thanks :)

{
if (isShutdown())
{
OTEL_INTERNAL_LOG_ERROR("[OStream Metric] Exporting "
<< records.size() << " records(s) failed, exporter is shutdown");
<< data.point_data_attr_.size()
<< " records(s) failed, exporter is shutdown");
return sdk::common::ExportResult::kFailure;
}

for (auto &record : records)
for (auto &record : data.point_data_attr_)
{
sout_ << "{"
<< "\n name : " << record->instrumentation_library_->GetName()
<< "\n version : " << record->instrumentation_library_->GetVersion();
printPointData(record->point_data_);
sout_ << "{";
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)
void OStreamMetricExporter::printPointData(const 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_))
{
Expand All @@ -76,8 +68,6 @@ void OStreamMetricExporter::printPointData(opentelemetry::sdk::metrics::PointTyp
{
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_))
Expand All @@ -90,14 +80,14 @@ void OStreamMetricExporter::printPointData(opentelemetry::sdk::metrics::PointTyp
}

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

Expand All @@ -109,8 +99,8 @@ void OStreamMetricExporter::printPointData(opentelemetry::sdk::metrics::PointTyp
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_;
<< std::to_string(last_point_data.sample_ts_.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_))
{
Expand Down