diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/jaegertracing/opentelemetry-cpp/exporters/ostream | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/exporters/ostream')
16 files changed, 2636 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/BUILD b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/BUILD new file mode 100644 index 000000000..917b70450 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/BUILD @@ -0,0 +1,131 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "ostream_log_exporter", + srcs = [ + "src/log_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/ostream/common_utils.h", + "include/opentelemetry/exporters/ostream/log_exporter.h", + ], + strip_include_prefix = "include", + tags = ["ostream"], + deps = [ + "//sdk/src/logs", + ], +) + +cc_test( + name = "ostream_log_test", + srcs = ["test/ostream_log_test.cc"], + tags = [ + "ostream", + "test", + ], + deps = [ + ":ostream_log_exporter", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "ostream_metrics_exporter_deprecated", + srcs = [ + "src/metrics_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/ostream/metrics_exporter.h", + ], + strip_include_prefix = "include", + tags = ["ostream"], + deps = [ + "//sdk/src/_metrics:metrics_deprecated", + ], +) + +cc_library( + name = "ostream_metric_exporter", + srcs = [ + "src/metric_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/ostream/common_utils.h", + "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_deprecated", + srcs = ["test/ostream_metrics_test.cc"], + tags = [ + "ostream", + "test", + ], + deps = [ + ":ostream_metrics_exporter_deprecated", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "ostream_span_exporter", + srcs = [ + "src/span_exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/ostream/common_utils.h", + "include/opentelemetry/exporters/ostream/span_exporter.h", + ], + strip_include_prefix = "include", + tags = ["ostream"], + deps = [ + "//sdk/src/trace", + ], +) + +cc_library( + name = "ostream_capture", + hdrs = [ + "test/ostream_capture.h", + ], + tags = ["ostream"], + deps = [ + "//api", + ], +) + +cc_test( + name = "ostream_span_test", + srcs = ["test/ostream_span_test.cc"], + tags = [ + "ostream", + "test", + ], + deps = [ + ":ostream_capture", + ":ostream_span_exporter", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/CMakeLists.txt new file mode 100644 index 000000000..db2562ddd --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/CMakeLists.txt @@ -0,0 +1,125 @@ +add_library(opentelemetry_exporter_ostream_span src/span_exporter.cc) + +set_target_properties(opentelemetry_exporter_ostream_span + PROPERTIES EXPORT_NAME ostream_span_exporter) + +target_include_directories( + opentelemetry_exporter_ostream_span + PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>") + +target_link_libraries(opentelemetry_exporter_ostream_span + PUBLIC opentelemetry_trace) + +install( + TARGETS opentelemetry_exporter_ostream_span + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "*.h" + PATTERN "metrics_exporter.h" EXCLUDE + PATTERN "log_Exporter.h" EXCLUDE) + +if(BUILD_TESTING) + add_executable(ostream_span_test test/ostream_span_test.cc) + target_link_libraries(ostream_span_test ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_ostream_span) + gtest_add_tests( + TARGET ostream_span_test + TEST_PREFIX exporter. + TEST_LIST ostream_span_test) +endif() # BUILD_TESTING + +if(WITH_METRICS_PREVIEW) + add_library(opentelemetry_exporter_ostream_metrics_deprecated + src/metrics_exporter.cc) + set_target_properties(opentelemetry_exporter_ostream_metrics_deprecated + PROPERTIES EXPORT_NAME ostream_metrics_exporter) + target_include_directories( + opentelemetry_exporter_ostream_metrics_deprecated + PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>") + target_link_libraries(opentelemetry_exporter_ostream_metrics_deprecated + PUBLIC opentelemetry_metrics_deprecated) + install( + TARGETS opentelemetry_exporter_ostream_metrics_deprecated + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "metrics_exporter.h") + if(BUILD_TESTING) + add_executable(ostream_metrics_test test/ostream_metrics_test.cc) + target_link_libraries(ostream_metrics_test ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_ostream_metrics_deprecated) + gtest_add_tests( + TARGET ostream_metrics_test + TEST_PREFIX exporter. + TEST_LIST ostream_metrics_test) + endif() +else() + add_library(opentelemetry_exporter_ostream_metrics src/metric_exporter.cc) + set_target_properties(opentelemetry_exporter_ostream_metrics + PROPERTIES EXPORT_NAME ostream_metrics_exporter) + target_include_directories( + opentelemetry_exporter_ostream_metrics + PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>") + target_link_libraries(opentelemetry_exporter_ostream_metrics + PUBLIC opentelemetry_metrics) + install( + TARGETS opentelemetry_exporter_ostream_metrics + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "metric_exporter.h") + if(BUILD_TESTING) + add_executable(ostream_metric_test test/ostream_metric_test.cc) + target_link_libraries( + ostream_metric_test ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_ostream_metrics opentelemetry_resources) + gtest_add_tests( + TARGET ostream_metric_test + TEST_PREFIX exporter. + TEST_LIST ostream_metric_test) + endif() +endif() + +if(WITH_LOGS_PREVIEW) + add_library(opentelemetry_exporter_ostream_logs src/log_exporter.cc) + set_target_properties(opentelemetry_exporter_ostream_logs + PROPERTIES EXPORT_NAME ostream_log_exporter) + target_include_directories( + opentelemetry_exporter_ostream_logs + PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>") + target_link_libraries(opentelemetry_exporter_ostream_logs + PUBLIC opentelemetry_logs) + install( + TARGETS opentelemetry_exporter_ostream_logs + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "log_exporter.h") + if(BUILD_TESTING) + add_executable(ostream_log_test test/ostream_log_test.cc) + target_link_libraries(ostream_log_test ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_ostream_logs) + gtest_add_tests( + TARGET ostream_log_test + TEST_PREFIX exporter. + TEST_LIST ostream_log_test) + endif() +endif() diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/common_utils.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/common_utils.h new file mode 100644 index 000000000..cfebfe8fc --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/common_utils.h @@ -0,0 +1,80 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include <sstream> +#include <string> +#include <vector> +#include "opentelemetry/nostd/variant.h" +#include "opentelemetry/sdk/common/attribute_utils.h" + +#pragma once +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace ostream_common +{ +/* + print_value is used to print out the value of an attribute within a vector. + These values are held in a variant which makes the process of printing them much more + complicated. +*/ + +template <typename T> +void print_value(const T &item, std::ostream &sout) +{ + sout << item; +} + +template <typename T> +void print_value(const std::vector<T> &vec, std::ostream &sout) +{ + sout << '['; + size_t i = 1; + size_t sz = vec.size(); + for (auto v : vec) + { + sout << v; + if (i != sz) + sout << ','; + i++; + }; + sout << ']'; +} + +// Prior to C++14, generic lambda is not available so fallback to functor. +#if __cplusplus < 201402L + +class OwnedAttributeValueVisitor +{ +public: + OwnedAttributeValueVisitor(std::ostream &sout) : sout_(sout) {} + + template <typename T> + void operator()(T &&arg) + { + print_value(arg, sout_); + } + +private: + std::ostream &sout_; +}; + +#endif + +void print_value(const opentelemetry::sdk::common::OwnedAttributeValue &value, std::ostream &sout) +{ +#if __cplusplus < 201402L + opentelemetry::nostd::visit(OwnedAttributeValueVisitor(sout), value); +#else + opentelemetry::nostd::visit( + [&sout](auto &&arg) { + /* explicit this is needed by some gcc versions (observed with v5.4.0)*/ + print_value(arg, sout); + }, + value); +#endif +} + +} // namespace ostream_common +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/log_exporter.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/log_exporter.h new file mode 100644 index 000000000..2f6acbb48 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/log_exporter.h @@ -0,0 +1,62 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/common/spin_lock_mutex.h" +# include "opentelemetry/nostd/type_traits.h" +# include "opentelemetry/sdk/logs/exporter.h" +# include "opentelemetry/sdk/logs/log_record.h" +# include "opentelemetry/version.h" + +# include <iostream> +# include <sstream> + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace logs +{ +/** + * The OStreamLogExporter exports logs through an ostream (default set to std::cout) + */ +class OStreamLogExporter final : public opentelemetry::sdk::logs::LogExporter +{ +public: + /** + * Create an OStreamLogExporter. This constructor takes in a reference to an ostream that the + * Export() method will send log data into. The default ostream is set to stdout. + */ + explicit OStreamLogExporter(std::ostream &sout = std::cout) noexcept; + + std::unique_ptr<sdk::logs::Recordable> MakeRecordable() noexcept override; + + /** + * Exports a span of logs sent from the processor. + */ + opentelemetry::sdk::common::ExportResult Export( + const opentelemetry::nostd::span<std::unique_ptr<sdk::logs::Recordable>> &records) noexcept + override; + + /** + * Marks the OStream Log Exporter as shut down. + */ + bool Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + +private: + // The OStream to send the logs to + std::ostream &sout_; + // Whether this exporter has been shut down + bool is_shutdown_ = false; + mutable opentelemetry::common::SpinLockMutex lock_; + bool isShutdown() const noexcept; + void printAttributes( + const std::unordered_map<std::string, opentelemetry::sdk::common::OwnedAttributeValue> &map, + const std::string prefix = "\n\t"); +}; +} // namespace logs +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h new file mode 100644 index 000000000..e34332d77 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metric_exporter.h @@ -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/sdk/metrics/data/metric_data.h" +# include "opentelemetry/sdk/metrics/instruments.h" +# include "opentelemetry/sdk/metrics/metric_exporter.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 metrics data into. + * The default ostream is set to stdout + */ + explicit OStreamMetricExporter(std::ostream &sout = std::cout) noexcept; + + /** + * Export + * @param data metrics data + */ + sdk::common::ExportResult Export(const sdk::metrics::ResourceMetrics &data) 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 printInstrumentationInfoMetricData( + const sdk::metrics::InstrumentationInfoMetrics &info_metrics); + void printPointData(const opentelemetry::sdk::metrics::PointType &point_data); + void printPointAttributes(const opentelemetry::sdk::metrics::PointAttributes &point_attributes); +}; +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metrics_exporter.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metrics_exporter.h new file mode 100644 index 000000000..5ae168aa0 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/metrics_exporter.h @@ -0,0 +1,166 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_METRICS_PREVIEW + +# include <iostream> +# include <string> +# 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 exporter +{ +namespace metrics +{ + +/** + * The OStreamMetricsExporter exports record data through an ostream + */ +class OStreamMetricsExporter final : public opentelemetry::sdk::metrics::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; + + sdk::common::ExportResult Export( + const std::vector<opentelemetry::sdk::metrics::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(opentelemetry::sdk::metrics::AggregatorVariant value) + { + auto agg = nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>>(value); + auto aggKind = agg->get_aggregator_kind(); + + if (!agg) + return; + switch (aggKind) + { + case opentelemetry::sdk::metrics::AggregatorKind::Counter: { + sout_ << "\n sum : " << agg->get_checkpoint()[0]; + } + break; + case opentelemetry::sdk::metrics::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 opentelemetry::sdk::metrics::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 opentelemetry::sdk::metrics::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(); + size_t size = vec.size(); + size_t i = 1; + + sout_ << "\n values : " << '['; + + for (auto val : vec) + { + sout_ << val; + if (i != size) + sout_ << ", "; + i++; + } + sout_ << ']'; + } + } + break; + case opentelemetry::sdk::metrics::AggregatorKind::Histogram: { + auto boundaries = agg->get_boundaries(); + auto counts = agg->get_counts(); + + size_t boundaries_size = boundaries.size(); + size_t counts_size = counts.size(); + + sout_ << "\n buckets : " << '['; + + for (size_t i = 0; i < boundaries_size; i++) + { + sout_ << boundaries[i]; + + if (i != boundaries_size - 1) + sout_ << ", "; + } + sout_ << ']'; + + sout_ << "\n counts : " << '['; + for (size_t i = 0; i < counts_size; i++) + { + sout_ << counts[i]; + + if (i != counts_size - 1) + sout_ << ", "; + } + sout_ << ']'; + } + break; + case opentelemetry::sdk::metrics::AggregatorKind::Sketch: { + auto boundaries = agg->get_boundaries(); + auto counts = agg->get_counts(); + + size_t boundaries_size = boundaries.size(); + size_t counts_size = counts.size(); + + sout_ << "\n buckets : " << '['; + + for (size_t i = 0; i < boundaries_size; i++) + { + sout_ << boundaries[i]; + + if (i != boundaries_size - 1) + sout_ << ", "; + } + sout_ << ']'; + + sout_ << "\n counts : " << '['; + for (size_t i = 0; i < counts_size; i++) + { + sout_ << counts[i]; + + if (i != counts_size - 1) + sout_ << ", "; + } + sout_ << ']'; + } + break; + } + } +}; +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h new file mode 100644 index 000000000..c8603db02 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h @@ -0,0 +1,70 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/common/spin_lock_mutex.h" +#include "opentelemetry/nostd/type_traits.h" +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/version.h" + +#include <iostream> +#include <map> +#include <sstream> + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace trace +{ + +/** + * The OStreamSpanExporter exports span data through an ostream + */ +class OStreamSpanExporter final : public opentelemetry::sdk::trace::SpanExporter +{ +public: + /** + * Create an OStreamSpanExporter. 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 OStreamSpanExporter(std::ostream &sout = std::cout) noexcept; + + std::unique_ptr<opentelemetry::sdk::trace::Recordable> MakeRecordable() noexcept override; + + sdk::common::ExportResult Export( + const opentelemetry::nostd::span<std::unique_ptr<opentelemetry::sdk::trace::Recordable>> + &spans) noexcept override; + + bool Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + +private: + std::ostream &sout_; + bool is_shutdown_ = false; + mutable opentelemetry::common::SpinLockMutex lock_; + bool isShutdown() const noexcept; + + // Mapping status number to the string from api/include/opentelemetry/trace/canonical_code.h + std::map<int, std::string> statusMap{{0, "Unset"}, {1, "Ok"}, {2, "Error"}}; + + // various print helpers + void printAttributes( + const std::unordered_map<std::string, opentelemetry::sdk::common::OwnedAttributeValue> &map, + const std::string prefix = "\n\t"); + + void printEvents(const std::vector<opentelemetry::sdk::trace::SpanDataEvent> &events); + + void printLinks(const std::vector<opentelemetry::sdk::trace::SpanDataLink> &links); + + void printResources(const opentelemetry::sdk::resource::Resource &resources); + + void printInstrumentationLibrary( + const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary + &instrumentation_library); +}; +} // namespace trace +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/log_exporter.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/log_exporter.cc new file mode 100644 index 000000000..e6ddd4c9f --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/log_exporter.cc @@ -0,0 +1,132 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/exporters/ostream/log_exporter.h" +# include <mutex> +# include "opentelemetry/exporters/ostream/common_utils.h" +# include "opentelemetry/sdk_config.h" + +# include <iostream> +# include <type_traits> + +namespace nostd = opentelemetry::nostd; +namespace sdklogs = opentelemetry::sdk::logs; +namespace sdkcommon = opentelemetry::sdk::common; +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace logs +{ + +/*********************** Constructor ***********************/ + +OStreamLogExporter::OStreamLogExporter(std::ostream &sout) noexcept : sout_(sout) {} + +/*********************** Exporter methods ***********************/ + +std::unique_ptr<sdklogs::Recordable> OStreamLogExporter::MakeRecordable() noexcept +{ + return std::unique_ptr<sdklogs::Recordable>(new sdklogs::LogRecord()); +} + +sdk::common::ExportResult OStreamLogExporter::Export( + const nostd::span<std::unique_ptr<sdklogs::Recordable>> &records) noexcept +{ + if (isShutdown()) + { + OTEL_INTERNAL_LOG_ERROR("[Ostream Log Exporter] Exporting " + << records.size() << " log(s) failed, exporter is shutdown"); + return sdk::common::ExportResult::kFailure; + } + + for (auto &record : records) + { + // Convert recordable to a LogRecord so that the getters of the LogRecord can be used + auto log_record = + std::unique_ptr<sdklogs::LogRecord>(static_cast<sdklogs::LogRecord *>(record.release())); + + if (log_record == nullptr) + { + // TODO: Log Internal SDK error "recordable data was lost" + continue; + } + + // Convert trace, spanid, traceflags into exportable representation + constexpr int trace_id_len = 32; + constexpr int span_id__len = 16; + constexpr int trace_flags_len = 2; + + char trace_id[trace_id_len] = {0}; + char span_id[span_id__len] = {0}; + char trace_flags[trace_flags_len] = {0}; + + log_record->GetTraceId().ToLowerBase16(trace_id); + log_record->GetSpanId().ToLowerBase16(span_id); + log_record->GetTraceFlags().ToLowerBase16(trace_flags); + + // Print out each field of the log record, noting that severity is separated + // into severity_num and severity_text + sout_ << "{\n" + << " timestamp : " << log_record->GetTimestamp().time_since_epoch().count() << "\n" + << " severity_num : " << static_cast<std::uint32_t>(log_record->GetSeverity()) << "\n" + << " severity_text : "; + + std::uint32_t severity_index = static_cast<std::uint32_t>(log_record->GetSeverity()); + if (severity_index >= std::extent<decltype(opentelemetry::logs::SeverityNumToText)>::value) + { + sout_ << "Invalid severity(" << severity_index << ")\n"; + } + else + { + sout_ << opentelemetry::logs::SeverityNumToText[severity_index] << "\n"; + } + + sout_ << " body : " << log_record->GetBody() << "\n" + << " resource : "; + + printAttributes(log_record->GetResource().GetAttributes()); + + sout_ << "\n" + << " attributes : "; + + printAttributes(log_record->GetAttributes()); + + sout_ << "\n" + << " trace_id : " << std::string(trace_id, trace_id_len) << "\n" + << " span_id : " << std::string(span_id, span_id__len) << "\n" + << " trace_flags : " << std::string(trace_flags, trace_flags_len) << "\n" + << "}\n"; + } + + return sdk::common::ExportResult::kSuccess; +} + +bool OStreamLogExporter::Shutdown(std::chrono::microseconds timeout) noexcept +{ + const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_); + is_shutdown_ = true; + return true; +} + +bool OStreamLogExporter::isShutdown() const noexcept +{ + const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_); + return is_shutdown_; +} + +void OStreamLogExporter::printAttributes( + const std::unordered_map<std::string, sdkcommon::OwnedAttributeValue> &map, + const std::string prefix) +{ + for (const auto &kv : map) + { + sout_ << prefix << kv.first << ": "; + opentelemetry::exporter::ostream_common::print_value(kv.second, sout_); + } +} + +} // namespace logs +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metric_exporter.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metric_exporter.cc new file mode 100644 index 000000000..2e90e0845 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metric_exporter.cc @@ -0,0 +1,214 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include <chrono> +#ifndef ENABLE_METRICS_PREVIEW +# include <algorithm> +# include "opentelemetry/exporters/ostream/common_utils.h" +# 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) +{ + std::time_t epoch_time = std::chrono::system_clock::to_time_t(time_stamp); + + struct tm *tm_ptr = nullptr; +# if defined(_MSC_VER) + struct tm buf_tm; + if (!gmtime_s(&buf_tm, &epoch_time)) + { + tm_ptr = &buf_tm; + } +# else + tm_ptr = std::gmtime(&epoch_time); +# endif + + char buf[100]; + char *date_str = nullptr; + if (tm_ptr == nullptr) + { + OTEL_INTERNAL_LOG_ERROR("[OStream Metric] gmtime failed for " << epoch_time); + } + else if (std::strftime(buf, sizeof(buf), "%c", tm_ptr) > 0) + { + date_str = buf; + } + else + { + OTEL_INTERNAL_LOG_ERROR("[OStream Metric] strftime failed for " << epoch_time); + } + + return std::string{date_str}; +} +} // 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 sdk::metrics::ResourceMetrics &data) noexcept +{ + if (isShutdown()) + { + OTEL_INTERNAL_LOG_ERROR("[OStream Metric] Exporting " + << data.instrumentation_info_metric_data_.size() + << " records(s) failed, exporter is shutdown"); + return sdk::common::ExportResult::kFailure; + } + + for (auto &record : data.instrumentation_info_metric_data_) + { + printInstrumentationInfoMetricData(record); + } + return sdk::common::ExportResult::kSuccess; +} + +void OStreamMetricExporter::printInstrumentationInfoMetricData( + const sdk::metrics::InstrumentationInfoMetrics &info_metric) +{ + // sout_ is shared + const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_); + 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_) + { + sout_ << "\n start time\t: " << timeToString(record.start_ts) + << "\n end time\t: " << timeToString(record.end_ts) + << "\n name\t\t: " << record.instrument_descriptor.name_ + << "\n description\t: " << record.instrument_descriptor.description_ + << "\n unit\t\t: " << record.instrument_descriptor.unit_; + + for (const auto &pd : record.point_data_attr_) + { + if (!nostd::holds_alternative<sdk::metrics::DropPointData>(pd.point_data)) + { + printPointData(pd.point_data); + printPointAttributes(pd.attributes); + } + } + } + sout_ << "\n}\n"; +} + +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\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_); + } + 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 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::list<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::list<long>>(histogram_point_data.boundaries_)) + { + auto &long_boundaries = nostd::get<std::list<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.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_)) + { + 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_); + } + } +} + +void OStreamMetricExporter::printPointAttributes( + const opentelemetry::sdk::metrics::PointAttributes &point_attributes) +{ + sout_ << "\n attributes\t\t: "; + for (const auto &kv : point_attributes) + { + sout_ << "\n\t" << kv.first << ": "; + opentelemetry::exporter::ostream_common::print_value(kv.second, sout_); + } +} + +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 diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metrics_exporter.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metrics_exporter.cc new file mode 100644 index 000000000..4f4bbfd06 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/metrics_exporter.cc @@ -0,0 +1,59 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_METRICS_PREVIEW +# include "opentelemetry/exporters/ostream/metrics_exporter.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace metrics +{ + +OStreamMetricsExporter::OStreamMetricsExporter(std::ostream &sout) noexcept : sout_(sout) {} + +sdk::common::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<opentelemetry::sdk::metrics::Aggregator<int>>>( + aggregator)) + { + PrintAggregatorVariant<int>(aggregator); + } + else if (nostd::holds_alternative< + std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator)) + { + PrintAggregatorVariant<short>(aggregator); + } + else if (nostd::holds_alternative< + std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator)) + { + PrintAggregatorVariant<double>(aggregator); + } + else if (nostd::holds_alternative< + std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator)) + { + PrintAggregatorVariant<float>(aggregator); + } + sout_ << "\n}\n"; + } + return sdk::common::ExportResult::kSuccess; +} + +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/span_exporter.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/span_exporter.cc new file mode 100644 index 000000000..226f98737 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/src/span_exporter.cc @@ -0,0 +1,178 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/ostream/span_exporter.h" +#include "opentelemetry/exporters/ostream/common_utils.h" + +#include <iostream> +#include <mutex> +#include "opentelemetry/sdk_config.h" + +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace trace_api = opentelemetry::trace; +namespace sdkcommon = opentelemetry::sdk::common; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace trace +{ + +std::ostream &operator<<(std::ostream &os, trace_api::SpanKind span_kind) +{ + switch (span_kind) + { + case trace_api::SpanKind::kClient: + return os << "Client"; + case trace_api::SpanKind::kInternal: + return os << "Internal"; + case trace_api::SpanKind::kServer: + return os << "Server"; + case trace_api::SpanKind::kProducer: + return os << "Producer"; + case trace_api::SpanKind::kConsumer: + return os << "Consumer"; + }; + return os << ""; +} + +OStreamSpanExporter::OStreamSpanExporter(std::ostream &sout) noexcept : sout_(sout) {} + +std::unique_ptr<trace_sdk::Recordable> OStreamSpanExporter::MakeRecordable() noexcept +{ + return std::unique_ptr<trace_sdk::Recordable>(new trace_sdk::SpanData); +} + +sdk::common::ExportResult OStreamSpanExporter::Export( + const nostd::span<std::unique_ptr<trace_sdk::Recordable>> &spans) noexcept +{ + if (isShutdown()) + { + OTEL_INTERNAL_LOG_ERROR("[Ostream Trace Exporter] Exporting " + << spans.size() << " span(s) failed, exporter is shutdown"); + return sdk::common::ExportResult::kFailure; + } + + for (auto &recordable : spans) + { + auto span = std::unique_ptr<trace_sdk::SpanData>( + static_cast<trace_sdk::SpanData *>(recordable.release())); + + if (span != nullptr) + { + + char trace_id[32] = {0}; + char span_id[16] = {0}; + char parent_span_id[16] = {0}; + + span->GetTraceId().ToLowerBase16(trace_id); + span->GetSpanId().ToLowerBase16(span_id); + span->GetParentSpanId().ToLowerBase16(parent_span_id); + + sout_ << "{" + << "\n name : " << span->GetName() + << "\n trace_id : " << std::string(trace_id, 32) + << "\n span_id : " << std::string(span_id, 16) + << "\n tracestate : " << span->GetSpanContext().trace_state()->ToHeader() + << "\n parent_span_id: " << std::string(parent_span_id, 16) + << "\n start : " << span->GetStartTime().time_since_epoch().count() + << "\n duration : " << span->GetDuration().count() + << "\n description : " << span->GetDescription() + << "\n span kind : " << span->GetSpanKind() + << "\n status : " << statusMap[int(span->GetStatus())] + << "\n attributes : "; + printAttributes(span->GetAttributes()); + sout_ << "\n events : "; + printEvents(span->GetEvents()); + sout_ << "\n links : "; + printLinks(span->GetLinks()); + sout_ << "\n resources : "; + printResources(span->GetResource()); + sout_ << "\n instr-lib : "; + printInstrumentationLibrary(span->GetInstrumentationLibrary()); + sout_ << "\n}\n"; + } + } + + return sdk::common::ExportResult::kSuccess; +} + +bool OStreamSpanExporter::Shutdown(std::chrono::microseconds timeout) noexcept +{ + const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_); + is_shutdown_ = true; + return true; +} + +bool OStreamSpanExporter::isShutdown() const noexcept +{ + const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_); + return is_shutdown_; +} +void OStreamSpanExporter::printAttributes( + const std::unordered_map<std::string, sdkcommon::OwnedAttributeValue> &map, + const std::string prefix) +{ + for (const auto &kv : map) + { + sout_ << prefix << kv.first << ": "; + opentelemetry::exporter::ostream_common::print_value(kv.second, sout_); + } +} + +void OStreamSpanExporter::printEvents(const std::vector<trace_sdk::SpanDataEvent> &events) +{ + for (const auto &event : events) + { + sout_ << "\n\t{" + << "\n\t name : " << event.GetName() + << "\n\t timestamp : " << event.GetTimestamp().time_since_epoch().count() + << "\n\t attributes : "; + printAttributes(event.GetAttributes(), "\n\t\t"); + sout_ << "\n\t}"; + } +} + +void OStreamSpanExporter::printLinks(const std::vector<trace_sdk::SpanDataLink> &links) +{ + for (const auto &link : links) + { + char trace_id[32] = {0}; + char span_id[16] = {0}; + link.GetSpanContext().trace_id().ToLowerBase16(trace_id); + link.GetSpanContext().span_id().ToLowerBase16(span_id); + sout_ << "\n\t{" + << "\n\t trace_id : " << std::string(trace_id, 32) + << "\n\t span_id : " << std::string(span_id, 16) + << "\n\t tracestate : " << link.GetSpanContext().trace_state()->ToHeader() + << "\n\t attributes : "; + printAttributes(link.GetAttributes(), "\n\t\t"); + sout_ << "\n\t}"; + } +} + +void OStreamSpanExporter::printResources(const opentelemetry::sdk::resource::Resource &resources) +{ + auto attributes = resources.GetAttributes(); + if (attributes.size()) + { + printAttributes(attributes, "\n\t"); + } +} + +void OStreamSpanExporter::printInstrumentationLibrary( + const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary + &instrumentation_library) +{ + sout_ << instrumentation_library.GetName(); + auto version = instrumentation_library.GetVersion(); + if (version.size()) + { + sout_ << "-" << version; + } +} + +} // namespace trace +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_capture.h b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_capture.h new file mode 100644 index 000000000..6c61c7152 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_capture.h @@ -0,0 +1,60 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <iostream> +#include <sstream> +#include <string> + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace ostream +{ +namespace test +{ +/** + * The OStreamCapture captures from the specified stream for its lifetime + */ +class OStreamCapture +{ +public: + /** + * Create a OStreamCapture which will capture the output of the ostream that it was constructed + * with for the lifetime of the instance. + */ + OStreamCapture(std::ostream &ostream) : stream_(ostream), buf_(ostream.rdbuf()) + { + stream_.rdbuf(captured_.rdbuf()); + } + + ~OStreamCapture() { stream_.rdbuf(buf_); } + + /** + * Returns the captured data from the stream. + */ + std::string GetCaptured() const { return captured_.str(); } + +private: + std::ostream &stream_; + std::streambuf *buf_; + std::stringstream captured_; +}; + +/** + * Helper method to invoke the passed func while recording the output of the specified stream and + * return the output afterwards. + */ +template <typename Func> +std::string WithOStreamCapture(std::ostream &stream, Func func) +{ + OStreamCapture capture(stream); + func(); + return capture.GetCaptured(); +} + +} // namespace test +} // namespace ostream +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_log_test.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_log_test.cc new file mode 100644 index 000000000..91d8fbf24 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_log_test.cc @@ -0,0 +1,330 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include <array> +# include "opentelemetry/exporters/ostream/log_exporter.h" +# include "opentelemetry/logs/provider.h" +# include "opentelemetry/nostd/span.h" +# include "opentelemetry/sdk/logs/logger_provider.h" +# include "opentelemetry/sdk/logs/simple_log_processor.h" + +# include <gtest/gtest.h> +# include <iostream> + +namespace sdklogs = opentelemetry::sdk::logs; +namespace logs_api = opentelemetry::logs; +namespace nostd = opentelemetry::nostd; +namespace exporterlogs = opentelemetry::exporter::logs; +namespace common = opentelemetry::common; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace logs +{ + +// Test that when OStream Log exporter is shutdown, no logs should be sent to stream +TEST(OStreamLogExporter, Shutdown) +{ + auto exporter = std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter); + + // Save cout's original buffer here + std::streambuf *original = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::stringstream output; + std::cout.rdbuf(output.rdbuf()); + + EXPECT_TRUE(exporter->Shutdown()); + + // After processor/exporter is shutdown, no logs should be sent to stream + auto record = exporter->MakeRecordable(); + record->SetBody("Log record not empty"); + exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1)); + + // Restore original stringstream buffer + std::cout.rdbuf(original); + std::string err_message = + "[Ostream Log Exporter] Exporting 1 log(s) failed, exporter is shutdown"; + EXPECT_TRUE(output.str().find(err_message) != std::string::npos); +} + +// ---------------------------------- Print to cout ------------------------- + +// Testing what a default log record that has no values changed will print out +// This function tests MakeRecordable() as well as Export(). +TEST(OstreamLogExporter, DefaultLogRecordToCout) +{ + auto exporter = + std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter(std::cout)); + + // Save cout's original buffer here + std::streambuf *original = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::stringstream output; + std::cout.rdbuf(output.rdbuf()); + + // Pass a default recordable created by the exporter to be exported + auto log_record = exporter->MakeRecordable(); + exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&log_record, 1)); + + // Restore cout's original stringstream + std::cout.rdbuf(original); + + std::vector<std::string> expected_output{ + "{\n" + " timestamp : 0\n" + " severity_num : 0\n" + " severity_text : INVALID\n" + " body : \n", + " resource : \n", + "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + "telemetry.sdk.name: opentelemetry\n", + "telemetry.sdk.language: cpp\n", + " attributes : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " trace_flags : 00\n" + "}\n"}; + + for (auto &expected : expected_output) + { + ASSERT_NE(output.str().find(expected), std::string::npos); + } +} + +// Testing what a log record with only the "timestamp", "severity", "name" and "message" fields set, +// will print out +TEST(OStreamLogExporter, SimpleLogToCout) +{ + // Initialize an Ostream exporter to std::cout + auto exporter = + std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter(std::cout)); + + // Save original stream buffer, then redirect cout to our new stream buffer + std::streambuf *original = std::cout.rdbuf(); + std::stringstream output; + std::cout.rdbuf(output.rdbuf()); + + // Pass a default recordable created by the exporter to be exported + // Create a log record and manually timestamp, severity, name, message + common::SystemTimestamp now(std::chrono::system_clock::now()); + + auto record = std::unique_ptr<sdklogs::Recordable>(new sdklogs::LogRecord()); + record->SetTimestamp(now); + record->SetSeverity(logs_api::Severity::kTrace); // kTrace has enum value of 1 + record->SetBody("Message"); + + // Log a record to cout + exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1)); + + // Reset cout's original stringstream buffer + std::cout.rdbuf(original); + + std::vector<std::string> expected_output{ + "{\n" + " timestamp : " + + std::to_string(now.time_since_epoch().count()) + + "\n" + " severity_num : 1\n" + " severity_text : TRACE\n" + " body : Message\n", + " resource : \n", + "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + "telemetry.sdk.name: opentelemetry\n", + "telemetry.sdk.language: cpp\n", + " attributes : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " trace_flags : 00\n" + "}\n"}; + + for (auto &expected : expected_output) + { + ASSERT_NE(output.str().find(expected), std::string::npos); + } +} + +// ---------------------------------- Print to cerr -------------------------- + +// Testing what a log record with only the "resource" and "attributes" fields +// (i.e. KeyValueIterable types) set with primitive types, will print out +TEST(OStreamLogExporter, LogWithStringAttributesToCerr) +{ + // Initialize an Ostream exporter to cerr + auto exporter = + std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter(std::cerr)); + + // Save original stream buffer, then redirect cout to our new stream buffer + std::streambuf *original = std::cerr.rdbuf(); + std::stringstream stdcerrOutput; + std::cerr.rdbuf(stdcerrOutput.rdbuf()); + + // Pass a recordable created by the exporter to be exported + auto record = exporter->MakeRecordable(); + + // Set resources for this log record only of type <string, string> + auto resource = opentelemetry::sdk::resource::Resource::Create({{"key1", "val1"}}); + record->SetResource(resource); + + // Set attributes to this log record of type <string, AttributeValue> + record->SetAttribute("a", true); + + // Log record to cerr + exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1)); + + // Reset cerr's original stringstream buffer + std::cerr.rdbuf(original); + + std::vector<std::string> expected_output{ + "{\n" + " timestamp : 0\n" + " severity_num : 0\n" + " severity_text : INVALID\n" + " body : \n", + " resource : \n", + "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + "telemetry.sdk.name: opentelemetry\n", + "telemetry.sdk.language: cpp\n", + "service.name: unknown_service\n", + "key1: val1\n", + " attributes : \n", + "\ta: 1\n", + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " trace_flags : 00\n" + "}\n"}; + + for (auto &expected : expected_output) + { + ASSERT_NE(stdcerrOutput.str().find(expected), std::string::npos); + } +} + +// ---------------------------------- Print to clog ------------------------- + +// Testing what a log record with only the "resource", and "attributes" fields +// (i.e. KeyValueIterable types), set with 2D arrays as values, will print out +TEST(OStreamLogExporter, LogWithVariantTypesToClog) +{ + + // Initialize an Ostream exporter to cerr + auto exporter = + std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter(std::clog)); + + // Save original stream buffer, then redirect cout to our new stream buffer + std::streambuf *original = std::clog.rdbuf(); + std::stringstream stdclogOutput; + std::clog.rdbuf(stdclogOutput.rdbuf()); + + // Pass a recordable created by the exporter to be exported + auto record = exporter->MakeRecordable(); + + // Set resources for this log record of only integer types as the value + std::array<int, 3> array1 = {1, 2, 3}; + nostd::span<int> data1{array1.data(), array1.size()}; + + auto resource = opentelemetry::sdk::resource::Resource::Create({{"res1", data1}}); + record->SetResource(resource); + + // Set resources for this log record of bool types as the value + // e.g. key/value is a par of type <string, array of bools> + std::array<bool, 3> array = {false, true, false}; + record->SetAttribute("attr1", nostd::span<bool>{array.data(), array.size()}); + + // Log a record to clog + exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1)); + + // Reset clog's original stringstream buffer + std::clog.rdbuf(original); + + std::vector<std::string> expected_output{ + "{\n" + " timestamp : 0\n" + " severity_num : 0\n" + " severity_text : INVALID\n" + " body : \n", + " resource : \n", + "service.name: unknown_service\n", + "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + "telemetry.sdk.name: opentelemetry\n", + "telemetry.sdk.language: cpp\n", + "res1: [1,2,3]\n", + "attributes : \n", + "\tattr1: [0,1,0]\n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " trace_flags : 00\n" + "}\n"}; + + for (auto &expected : expected_output) + { + ASSERT_NE(stdclogOutput.str().find(expected), std::string::npos); + } +} + +// // ---------------------------------- Integration Tests ------------------------- + +// Test using the simple log processor and ostream exporter to cout +// and use the rest of the logging pipeline (Logger, LoggerProvider, Provider) as well +TEST(OStreamLogExporter, IntegrationTest) +{ + // Initialize a logger + auto exporter = std::unique_ptr<sdklogs::LogExporter>(new exporterlogs::OStreamLogExporter); + auto sdkProvider = std::shared_ptr<sdklogs::LoggerProvider>(new sdklogs::LoggerProvider()); + sdkProvider->AddProcessor( + std::unique_ptr<sdklogs::LogProcessor>(new sdklogs::SimpleLogProcessor(std::move(exporter)))); + auto apiProvider = nostd::shared_ptr<logs_api::LoggerProvider>(sdkProvider); + auto provider = nostd::shared_ptr<logs_api::LoggerProvider>(apiProvider); + logs_api::Provider::SetLoggerProvider(provider); + const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; + auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger( + "Logger", "", "opentelelemtry_library", "", schema_url); + + // Back up cout's streambuf + std::streambuf *original = std::cout.rdbuf(); + + // Redirect cout to our string stream + std::stringstream stdcoutOutput; + std::cout.rdbuf(stdcoutOutput.rdbuf()); + + // Write a log to ostream exporter + common::SystemTimestamp now(std::chrono::system_clock::now()); + logger->Log(logs_api::Severity::kDebug, "Hello", {}, {}, {}, {}, now); + + // Restore cout's original streambuf + std::cout.rdbuf(original); + + // Compare actual vs expected outputs + std::vector<std::string> expected_output{ + "{\n" + " timestamp : " + + std::to_string(now.time_since_epoch().count()) + + "\n" + " severity_num : 5\n" + " severity_text : DEBUG\n" + " body : Hello\n", + " resource : \n", + "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + "service.name: unknown_service\n", + "telemetry.sdk.name: opentelemetry\n", + "telemetry.sdk.language: cpp\n", + " attributes : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " trace_flags : 00\n" + "}\n"}; + + for (auto &expected : expected_output) + { + ASSERT_NE(stdcoutOutput.str().find(expected), std::string::npos); + } +} + +} // namespace logs +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metric_test.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metric_test.cc new file mode 100644 index 000000000..45d6d8f88 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metric_test.cc @@ -0,0 +1,269 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +#ifndef ENABLE_METRICS_PREVIEW + +# include <gtest/gtest.h> +# include <memory> +# include <vector> +# include "opentelemetry/sdk/metrics/instruments.h" +# include "opentelemetry/sdk/resource/resource_detector.h" + +# include <iostream> +# 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/metrics/data/metric_data.h" +# include "opentelemetry/sdk/resource/resource.h" + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace exportermetrics = opentelemetry::exporter::metrics; + +TEST(OStreamMetricsExporter, Shutdown) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricExporter>(new exportermetrics::OStreamMetricExporter); + ASSERT_TRUE(exporter->Shutdown()); + auto result = exporter->Export(metric_sdk::ResourceMetrics{}); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kFailure); +} + +TEST(OStreamMetricsExporter, ExportSumPointData) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricExporter>(new exportermetrics::OStreamMetricExporter); + + metric_sdk::SumPointData sum_point_data{}; + sum_point_data.value_ = 10.0; + metric_sdk::SumPointData sum_point_data2{}; + sum_point_data2.value_ = 20.0; + metric_sdk::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.2.0"); + metric_sdk::MetricData metric_data{ + metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", + metric_sdk::InstrumentType::kCounter, + metric_sdk::InstrumentValueType::kDouble}, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector<metric_sdk::PointDataAttributes>{ + {metric_sdk::PointAttributes{{"a1", "b1"}}, sum_point_data}, + {metric_sdk::PointAttributes{{"a1", "b1"}}, sum_point_data2}}}; + data.instrumentation_info_metric_data_ = std::vector<metric_sdk::InstrumentationInfoMetrics>{ + {instrumentation_library.get(), std::vector<metric_sdk::MetricData>{metric_data}}}; + + std::stringstream stdoutOutput; + std::streambuf *sbuf = std::cout.rdbuf(); + std::cout.rdbuf(stdoutOutput.rdbuf()); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + std::cout.rdbuf(sbuf); + + std::string expected_output = + "{" + "\n name\t\t: library_name" + "\n schema url\t: " + "\n version\t: 1.2.0" + "\n start time\t: Thu Jan 1 00:00:00 1970" + "\n end time\t: Thu Jan 1 00:00:00 1970" + "\n name\t\t: library_name" + "\n description\t: description" + "\n unit\t\t: unit" + "\n type\t\t: SumPointData" + "\n value\t\t: 10" + "\n attributes\t\t: " + "\n\ta1: b1" + "\n type\t\t: SumPointData" + "\n value\t\t: 20" + "\n attributes\t\t: " + "\n\ta1: b1" + "\n}\n"; + ASSERT_EQ(stdoutOutput.str(), expected_output); +} + +TEST(OStreamMetricsExporter, ExportHistogramPointData) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricExporter>(new exportermetrics::OStreamMetricExporter); + + metric_sdk::HistogramPointData histogram_point_data{}; + histogram_point_data.boundaries_ = std::list<double>{10.1, 20.2, 30.2}; + histogram_point_data.count_ = 3; + histogram_point_data.counts_ = {200, 300, 400, 500}; + histogram_point_data.sum_ = 900.5; + metric_sdk::HistogramPointData histogram_point_data2{}; + histogram_point_data2.boundaries_ = std::list<long>{10, 20, 30}; + histogram_point_data2.count_ = 3; + histogram_point_data2.counts_ = {200, 300, 400, 500}; + histogram_point_data2.sum_ = 900l; + metric_sdk::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.2.0"); + metric_sdk::MetricData metric_data{ + metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", + metric_sdk::InstrumentType::kCounter, + metric_sdk::InstrumentValueType::kDouble}, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector<metric_sdk::PointDataAttributes>{ + {metric_sdk::PointAttributes{{"a1", "b1"}, {"a2", "b2"}}, histogram_point_data}, + {metric_sdk::PointAttributes{{"a1", "b1"}}, histogram_point_data2}}}; + data.instrumentation_info_metric_data_ = std::vector<metric_sdk::InstrumentationInfoMetrics>{ + {instrumentation_library.get(), std::vector<metric_sdk::MetricData>{metric_data}}}; + + std::stringstream stdoutOutput; + std::streambuf *sbuf = std::cout.rdbuf(); + std::cout.rdbuf(stdoutOutput.rdbuf()); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + std::cout.rdbuf(sbuf); + + std::string expected_output = + "{" + "\n name\t\t: library_name" + "\n schema url\t: " + "\n version\t: 1.2.0" + "\n start time\t: Thu Jan 1 00:00:00 1970" + "\n end time\t: Thu Jan 1 00:00:00 1970" + "\n name\t\t: library_name" + "\n description\t: description" + "\n unit\t\t: unit" + "\n type : HistogramPointData" + "\n count : 3" + "\n sum : 900.5" + "\n buckets : [10.1, 20.2, 30.2, ]" + "\n counts : [200, 300, 400, 500, ]" + "\n attributes\t\t: " + "\n\ta1: b1" + "\n\ta2: b2" + "\n type : HistogramPointData" + "\n count : 3" + "\n sum : 900" + "\n buckets : [10, 20, 30, ]" + "\n counts : [200, 300, 400, 500, ]" + "\n attributes\t\t: " + "\n\ta1: b1" + "\n}\n"; + ASSERT_EQ(stdoutOutput.str(), expected_output); +} + +TEST(OStreamMetricsExporter, ExportLastValuePointData) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricExporter>(new exportermetrics::OStreamMetricExporter); + + metric_sdk::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.2.0"); + metric_sdk::LastValuePointData last_value_point_data{}; + last_value_point_data.value_ = 10.0; + last_value_point_data.is_lastvalue_valid_ = true; + last_value_point_data.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + metric_sdk::LastValuePointData last_value_point_data2{}; + last_value_point_data2.value_ = 20l; + last_value_point_data2.is_lastvalue_valid_ = true; + last_value_point_data2.sample_ts_ = opentelemetry::common::SystemTimestamp{}; + metric_sdk::MetricData metric_data{ + metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", + metric_sdk::InstrumentType::kCounter, + metric_sdk::InstrumentValueType::kDouble}, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector<metric_sdk::PointDataAttributes>{ + {metric_sdk::PointAttributes{}, last_value_point_data}, + {metric_sdk::PointAttributes{}, last_value_point_data2}}}; + data.instrumentation_info_metric_data_ = std::vector<metric_sdk::InstrumentationInfoMetrics>{ + {instrumentation_library.get(), std::vector<metric_sdk::MetricData>{metric_data}}}; + + std::stringstream stdoutOutput; + std::streambuf *sbuf = std::cout.rdbuf(); + std::cout.rdbuf(stdoutOutput.rdbuf()); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + std::cout.rdbuf(sbuf); + + std::string expected_output = + "{" + "\n name\t\t: library_name" + "\n schema url\t: " + "\n version\t: 1.2.0" + "\n start time\t: Thu Jan 1 00:00:00 1970" + "\n end time\t: Thu Jan 1 00:00:00 1970" + "\n name\t\t: library_name" + "\n description\t: description" + "\n unit\t\t: unit" + "\n type : LastValuePointData" + "\n timestamp : 0" + "\n valid : true" + "\n value : 10" + "\n attributes\t\t: " + "\n type : LastValuePointData" + "\n timestamp : 0" + "\n valid : true" + "\n value : 20" + "\n attributes\t\t: " + "\n}\n"; + ASSERT_EQ(stdoutOutput.str(), expected_output); +} + +TEST(OStreamMetricsExporter, ExportDropPointData) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricExporter>(new exportermetrics::OStreamMetricExporter); + + metric_sdk::ResourceMetrics data; + auto resource = opentelemetry::sdk::resource::Resource::Create( + opentelemetry::sdk::resource::ResourceAttributes{}); + data.resource_ = &resource; + auto instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create("library_name", + "1.2.0"); + metric_sdk::DropPointData drop_point_data{}; + metric_sdk::DropPointData drop_point_data2{}; + metric_sdk::MetricData metric_data{ + metric_sdk::InstrumentDescriptor{"library_name", "description", "unit", + metric_sdk::InstrumentType::kCounter, + metric_sdk::InstrumentValueType::kDouble}, + opentelemetry::common::SystemTimestamp{}, opentelemetry::common::SystemTimestamp{}, + std::vector<metric_sdk::PointDataAttributes>{ + {metric_sdk::PointAttributes{}, drop_point_data}, + {metric_sdk::PointAttributes{}, drop_point_data2}}}; + data.instrumentation_info_metric_data_ = std::vector<metric_sdk::InstrumentationInfoMetrics>{ + {instrumentation_library.get(), std::vector<metric_sdk::MetricData>{metric_data}}}; + + std::stringstream stdoutOutput; + std::streambuf *sbuf = std::cout.rdbuf(); + std::cout.rdbuf(stdoutOutput.rdbuf()); + + auto result = exporter->Export(data); + EXPECT_EQ(result, opentelemetry::sdk::common::ExportResult::kSuccess); + std::cout.rdbuf(sbuf); + + std::string expected_output = + "{" + "\n name\t\t: library_name" + "\n schema url\t: " + "\n version\t: 1.2.0" + "\n start time\t: Thu Jan 1 00:00:00 1970" + "\n end time\t: Thu Jan 1 00:00:00 1970" + "\n name\t\t: library_name" + "\n description\t: description" + "\n unit\t\t: unit" + "\n}\n"; + + ASSERT_EQ(stdoutOutput.str(), expected_output); +} + +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metrics_test.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metrics_test.cc new file mode 100644 index 000000000..f5539c3d4 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_metrics_test.cc @@ -0,0 +1,295 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include <gtest/gtest.h> +#ifdef ENABLE_METRICS_PREVIEW + +# include "opentelemetry/exporters/ostream/metrics_exporter.h" +# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h" +# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h" +# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h" +# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h" +# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h" +# include "opentelemetry/sdk/_metrics/exporter.h" +# include "opentelemetry/sdk/_metrics/record.h" + +# include <iostream> + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace metrics_api = opentelemetry::metrics; +namespace nostd = opentelemetry::nostd; +namespace exportermetrics = opentelemetry::exporter::metrics; + +TEST(OStreamMetricsExporter, PrintCounter) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>( + new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter)); + + aggregator->update(5.5); + aggregator->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + std::vector<metric_sdk::Record> records; + records.push_back(r); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " sum : 5.5\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(OStreamMetricsExporter, PrintMinMaxSumCount) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>( + new metric_sdk::MinMaxSumCountAggregator<int>(metrics_api::InstrumentKind::Counter)); + + aggregator->update(1); + aggregator->update(2); + aggregator->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + std::vector<metric_sdk::Record> records; + records.push_back(r); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " min : 1\n" + " max : 2\n" + " sum : 3\n" + " count : 2\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(OStreamMetricsExporter, PrintGauge) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>( + new metric_sdk::GaugeAggregator<short>(metrics_api::InstrumentKind::Counter)); + + aggregator->update(1); + aggregator->update(9); + aggregator->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + std::vector<metric_sdk::Record> records; + records.push_back(r); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " last value : 9\n" + " timestamp : " + + std::to_string(aggregator->get_checkpoint_timestamp().time_since_epoch().count()) + + "\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(OStreamMetricsExporter, PrintExact) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>( + new metric_sdk::ExactAggregator<short>(metrics_api::InstrumentKind::Counter, true)); + + auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<short>>( + new metric_sdk::ExactAggregator<short>(metrics_api::InstrumentKind::Counter, false)); + + for (int i = 0; i < 10; i++) + { + aggregator->update(i); + aggregator2->update(i); + } + aggregator->checkpoint(); + aggregator2->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + metric_sdk::Record r2("name", "description", "labels", aggregator2); + std::vector<metric_sdk::Record> records; + records.push_back(r); + records.push_back(r2); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " quantiles : [0: 0, .25: 3, .50: 5, .75: 7, 1: 9]\n" + "}\n" + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " values : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(OStreamMetricsExporter, PrintHistogram) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + std::vector<double> boundaries{10, 20, 30, 40, 50}; + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>( + new metric_sdk::HistogramAggregator<float>(metrics_api::InstrumentKind::Counter, boundaries)); + + for (float i = 0; i < 60; i++) + { + aggregator->update(i); + } + aggregator->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + std::vector<metric_sdk::Record> records; + records.push_back(r); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " buckets : [10, 20, 30, 40, 50]\n" + " counts : [10, 10, 10, 10, 10, 10]\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} + +TEST(OStreamMetricsExporter, PrintSketch) +{ + auto exporter = + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter); + + std::vector<double> boundaries{1, 3, 5, 7, 9}; + auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>( + new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .000005)); + + for (int i = 0; i < 10; i++) + { + aggregator->update(i); + } + aggregator->checkpoint(); + + metric_sdk::Record r("name", "description", "labels", aggregator); + std::vector<metric_sdk::Record> records; + records.push_back(r); + + // Create stringstream to redirect to + std::stringstream stdoutOutput; + + // Save cout's buffer here + std::streambuf *sbuf = std::cout.rdbuf(); + + // Redirect cout to our stringstream buffer + std::cout.rdbuf(stdoutOutput.rdbuf()); + + exporter->Export(records); + + std::cout.rdbuf(sbuf); + + std::string expectedOutput = + "{\n" + " name : name\n" + " description : description\n" + " labels : labels\n" + " buckets : [0, 0.999995, 2, 3.00001, 4, 4.99999, 5.99997, 7.00003, 8.00003, 9]\n" + " counts : [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n" + "}\n"; + + ASSERT_EQ(stdoutOutput.str(), expectedOutput); +} +#else +TEST(OStreamMetricsExporter, DummyTest) +{ + // empty +} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_span_test.cc b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_span_test.cc new file mode 100644 index 000000000..edfd66505 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/exporters/ostream/test/ostream_span_test.cc @@ -0,0 +1,398 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/sdk/trace/recordable.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include "opentelemetry/sdk/trace/exporter.h" + +#include "opentelemetry/exporters/ostream/span_exporter.h" + +#include "ostream_capture.h" + +#include <gtest/gtest.h> +#include <iostream> + +using namespace opentelemetry::exporter::ostream::test; + +namespace trace = opentelemetry::trace; +namespace common = opentelemetry::common; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace resource = opentelemetry::sdk::resource; +namespace exportertrace = opentelemetry::exporter::trace; + +using Attributes = std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>; + +class TestResource : public resource::Resource +{ +public: + TestResource(resource::ResourceAttributes attributes = resource::ResourceAttributes()) + : resource::Resource(attributes) + {} +}; + +// Testing Shutdown functionality of OStreamSpanExporter, should expect no data to be sent to Stream +TEST(OStreamSpanExporter, Shutdown) +{ + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + recordable->SetName("Test Span"); + + // Capture the output of cout + const auto captured = WithOStreamCapture(std::cout, [&]() { + EXPECT_TRUE(processor->Shutdown()); + processor->OnEnd(std::move(recordable)); + }); + std::string err_message = + "[Ostream Trace Exporter] Exporting 1 span(s) failed, exporter is shutdown"; + EXPECT_TRUE(captured.find(err_message) != std::string::npos); +} + +constexpr const char *kDefaultSpanPrinted = + "{\n" + " name : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " tracestate : \n" + " parent_span_id: 0000000000000000\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " span kind : Internal\n" + " status : Unset\n" + " attributes : \n" + " events : \n" + " links : \n" + " resources : \n" + " instr-lib : unknown_service\n" + "}\n"; + +// Testing what a default span that is not changed will print out, either all 0's or empty values +TEST(OStreamSpanExporter, PrintDefaultSpan) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + processor->OnEnd(std::move(recordable)); + + EXPECT_EQ(output.str(), kDefaultSpanPrinted); +} + +TEST(OStreamSpanExporter, PrintSpanWithBasicFields) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t parent_span_id_buf[] = {8, 7, 6, 5, 4, 3, 2, 1}; + trace::TraceId trace_id{trace_id_buf}; + trace::SpanId span_id{span_id_buf}; + trace::SpanId parent_span_id{parent_span_id_buf}; + const auto trace_state = trace::TraceState::GetDefault()->Set("state1", "value"); + const trace::SpanContext span_context{ + trace_id, span_id, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true, trace_state}; + + recordable->SetIdentity(span_context, parent_span_id); + recordable->SetName("Test Span"); + common::SystemTimestamp now(std::chrono::system_clock::now()); + recordable->SetStartTime(now); + recordable->SetDuration(std::chrono::nanoseconds(100)); + recordable->SetStatus(trace::StatusCode::kOk, "Test Description"); + recordable->SetSpanKind(trace::SpanKind::kClient); + + TestResource resource1(resource::ResourceAttributes({{"key1", "val1"}})); + recordable->SetResource(resource1); + + processor->OnEnd(std::move(recordable)); + + std::string start = std::to_string(now.time_since_epoch().count()); + + std::string expectedOutput = + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " tracestate : state1=value\n" + " parent_span_id: 0807060504030201\n" + " start : " + + start + + "\n" + " duration : 100\n" + " description : Test Description\n" + " span kind : Client\n" + " status : Ok\n" + " attributes : \n" + " events : \n" + " links : \n" + " resources : \n" + "\tkey1: val1\n" + " instr-lib : unknown_service\n" + "}\n"; + EXPECT_EQ(output.str(), expectedOutput); +} + +TEST(OStreamSpanExporter, PrintSpanWithAttribute) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + recordable->SetAttribute("attr1", "string"); + + processor->OnEnd(std::move(recordable)); + + std::string expectedOutput = + "{\n" + " name : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " tracestate : \n" + " parent_span_id: 0000000000000000\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " span kind : Internal\n" + " status : Unset\n" + " attributes : \n" + "\tattr1: string\n" + " events : \n" + " links : \n" + " resources : \n" + " instr-lib : unknown_service\n" + "}\n"; + EXPECT_EQ(output.str(), expectedOutput); +} + +TEST(OStreamSpanExporter, PrintSpanWithArrayAttribute) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + std::array<int, 3> array1 = {1, 2, 3}; + nostd::span<int> span1{array1.data(), array1.size()}; + recordable->SetAttribute("array1", span1); + + processor->OnEnd(std::move(recordable)); + + std::string expectedOutput = + "{\n" + " name : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " tracestate : \n" + " parent_span_id: 0000000000000000\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " span kind : Internal\n" + " status : Unset\n" + " attributes : \n" + "\tarray1: [1,2,3]\n" + " events : \n" + " links : \n" + " resources : \n" + " instr-lib : unknown_service\n" + "}\n"; + EXPECT_EQ(output.str(), expectedOutput); +} + +TEST(OStreamSpanExporter, PrintSpanWithEvents) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + common::SystemTimestamp now(std::chrono::system_clock::now()); + common::SystemTimestamp next(std::chrono::system_clock::now() + std::chrono::seconds(1)); + + std::string now_str = std::to_string(now.time_since_epoch().count()); + std::string next_str = std::to_string(next.time_since_epoch().count()); + + recordable->AddEvent("hello", now); + recordable->AddEvent("world", next, + common::KeyValueIterableView<Attributes>({{"attr1", "string"}})); + + processor->OnEnd(std::move(recordable)); + + std::string expectedOutput = + "{\n" + " name : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " tracestate : \n" + " parent_span_id: 0000000000000000\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " span kind : Internal\n" + " status : Unset\n" + " attributes : \n" + " events : \n" + "\t{\n" + "\t name : hello\n" + "\t timestamp : " + + now_str + + "\n" + "\t attributes : \n" + "\t}\n" + "\t{\n" + "\t name : world\n" + "\t timestamp : " + + next_str + + "\n" + "\t attributes : \n" + "\t\tattr1: string\n" + "\t}\n" + " links : \n" + " resources : \n" + " instr-lib : unknown_service\n" + "}\n"; + EXPECT_EQ(output.str(), expectedOutput); +} + +TEST(OStreamSpanExporter, PrintSpanWithLinks) +{ + std::stringstream output; + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + // produce valid SpanContext with pseudo span and trace Id. + uint8_t span_id_buf[trace::SpanId::kSize] = { + 1, + }; + trace::SpanId span_id{span_id_buf}; + uint8_t trace_id_buf[trace::TraceId::kSize] = { + 2, + }; + trace::TraceId trace_id{trace_id_buf}; + const auto span_context = + trace::SpanContext(trace_id, span_id, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true); + + // and another to check preserving order. + uint8_t span_id_buf2[trace::SpanId::kSize] = { + 3, + }; + trace::SpanId span_id2{span_id_buf2}; + const auto span_context2 = + trace::SpanContext(trace_id, span_id2, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true, + trace::TraceState::FromHeader("state1=value")); + + recordable->AddLink(span_context); + recordable->AddLink(span_context2, + common::KeyValueIterableView<Attributes>({{"attr1", "string"}})); + + processor->OnEnd(std::move(recordable)); + + std::string expectedOutput = + "{\n" + " name : \n" + " trace_id : 00000000000000000000000000000000\n" + " span_id : 0000000000000000\n" + " tracestate : \n" + " parent_span_id: 0000000000000000\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " span kind : Internal\n" + " status : Unset\n" + " attributes : \n" + " events : \n" + " links : \n" + "\t{\n" + "\t trace_id : 02000000000000000000000000000000\n" + "\t span_id : 0100000000000000\n" + "\t tracestate : \n" + "\t attributes : \n" + "\t}\n" + "\t{\n" + "\t trace_id : 02000000000000000000000000000000\n" + "\t span_id : 0300000000000000\n" + "\t tracestate : state1=value\n" + "\t attributes : \n" + "\t\tattr1: string\n" + "\t}\n" + " resources : \n" + " instr-lib : unknown_service\n" + "}\n"; + EXPECT_EQ(output.str(), expectedOutput); +} + +// Test with the three common ostreams, tests are more of a sanity check and usage examples. +TEST(OStreamSpanExporter, PrintSpanToCout) +{ + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + const auto captured = + WithOStreamCapture(std::cout, [&]() { processor->OnEnd(std::move(recordable)); }); + + EXPECT_EQ(captured, kDefaultSpanPrinted); +} + +TEST(OStreamSpanExporter, PrintSpanToCerr) +{ + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(std::cerr)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + const auto captured = + WithOStreamCapture(std::cerr, [&]() { processor->OnEnd(std::move(recordable)); }); + + EXPECT_EQ(captured, kDefaultSpanPrinted); +} + +TEST(OStreamSpanExporter, PrintSpanToClog) +{ + auto exporter = + std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(std::clog)); + auto processor = std::shared_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + + auto recordable = processor->MakeRecordable(); + + const auto captured = + WithOStreamCapture(std::clog, [&]() { processor->OnEnd(std::move(recordable)); }); + + EXPECT_EQ(captured, kDefaultSpanPrinted); +} |