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
14 changes: 14 additions & 0 deletions examples/metrics_simple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,17 @@ cc_binary(
"//sdk/src/_metrics:metrics_deprecated",
],
)

cc_binary(
name = "metrics_ostream_example",
srcs = [
"metrics_ostream.cc",
],
linkopts = ["-pthread"],
tags = ["ostream"],
deps = [
"//api",
"//exporters/ostream:ostream_metric_exporter",
"//sdk/src/metrics",
],
)
70 changes: 70 additions & 0 deletions examples/metrics_simple/metrics_ostream.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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{"https://opentelemetry.io/schemas/1.2.0"};

// 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();
}
#else
int main() {}
#endif
59 changes: 29 additions & 30 deletions exporters/ostream/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,37 +43,36 @@ cc_library(
],
)

# TODO - Uncomment once MetricData interface is finalised
#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_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_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_deprecated",
Expand Down
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::ResourceMetrics &data) noexcept override;

/**
* Force flush the exporter.
Expand All @@ -60,7 +58,9 @@ 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 printInstrumentationInfoMetricData(
const sdk::metrics::InstrumentationInfoMetrics &info_metrics);
void printPointData(const opentelemetry::sdk::metrics::PointType &point_data);
};
} // namespace metrics
} // namespace exporter
Expand Down
93 changes: 59 additions & 34 deletions exporters/ostream/src/metric_exporter.cc
Original file line number Diff line number Diff line change
@@ -1,68 +1,95 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

namespace
{
std::string timeToString(opentelemetry::common::SystemTimestamp time_stamp)
{
auto duration = time_stamp.time_since_epoch().count();

std::chrono::nanoseconds dur(duration);
std::chrono::time_point<std::chrono::system_clock> dt(dur);
Copy link
Member

@lalitb lalitb Apr 11, 2022

Choose a reason for hiding this comment

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

nit - need to check, but I think this can be directly obtained by calling time_stamp()?

Copy link
Member Author

Choose a reason for hiding this comment

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

I try to print time in human readable format here. I didn't find any function similar.

Copy link
Member

@lalitb lalitb Apr 12, 2022

Choose a reason for hiding this comment

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

Not sure if something wrong with GitHub. I pasted a comment here, it was displayed multiple times and then when I removed one occurrence all of them removed :) But it was not that important, was thinking something to avoid couple of lines of code (so can be ignored):

std::string timeToString(opentelemetry::common::SystemTimestamp time_stamp)
{
  std::time_t epoch_time = std::chrono::system_clock::to_time_t(time_stamp());
  return std::ctime(&epoch_time);
}

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 your version.

std::time_t epoch_time = std::chrono::system_clock::to_time_t(dt);

return std::ctime(&epoch_time);
}
} // namespace

OPENTELEMETRY_BEGIN_NAMESPACE
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::ResourceMetrics &data) noexcept
{
if (isShutdown())
{
OTEL_INTERNAL_LOG_ERROR("[OStream Metric] Exporting "
<< records.size() << " records(s) failed, exporter is shutdown");
<< data.instrumentation_info_metric_data_.size()
<< " records(s) failed, exporter is shutdown");
return sdk::common::ExportResult::kFailure;
}

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

template <typename T>
inline void printVec(std::ostream &os, std::vector<T> &vec)
void OStreamMetricExporter::printInstrumentationInfoMetricData(
const sdk::metrics::InstrumentationInfoMetrics &info_metric)
{
os << '[';
if (vec.size() > 1)
{
std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<T>(os, ", "));
}
if (!vec.empty())
sout_ << "{";
sout_ << "\n name\t\t: " << info_metric.instrumentation_library_->GetName()
<< "\n schema url\t: " << info_metric.instrumentation_library_->GetSchemaURL()
<< "\n version\t: " << info_metric.instrumentation_library_->GetVersion();
for (const auto &record : info_metric.metric_data_)
{
os << vec.back();
sout_ << "\n start time\t: " << timeToString(record.start_ts)
<< " end time\t: " << timeToString(record.end_ts)
<< " description\t: " << record.instrument_descriptor.description_
<< "\n unit\t\t: " << record.instrument_descriptor.unit_;

for (const auto &pd : record.point_data_attr_)
{
printPointData(pd.point_data);
}
}
os << ']';
sout_ << "\n}\n";
}

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 : ";
sout_ << "\n type\t\t: SumPointData";
sout_ << "\n value\t\t: ";
if (nostd::holds_alternative<double>(sum_point_data.value_))
{
sout_ << nostd::get<double>(sum_point_data.value_);
Expand All @@ -76,8 +103,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 +115,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 +134,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
Loading