| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- #include <gtest/gtest.h>
- #include <stdint.h>
- #include <array>
- #include <chrono>
- #include <initializer_list>
- #include <iostream>
- #include <sstream>
- #include <string>
- #include <utility>
- #include "opentelemetry/common/attribute_value.h"
- #include "opentelemetry/common/key_value_iterable_view.h"
- #include "opentelemetry/common/timestamp.h"
- #include "opentelemetry/exporters/ostream/span_exporter.h"
- #include "opentelemetry/nostd/shared_ptr.h"
- #include "opentelemetry/nostd/span.h"
- #include "opentelemetry/nostd/string_view.h"
- #include "opentelemetry/sdk/resource/resource.h"
- #include "opentelemetry/sdk/trace/exporter.h"
- #include "opentelemetry/sdk/trace/processor.h"
- #include "opentelemetry/sdk/trace/recordable.h"
- #include "opentelemetry/sdk/trace/simple_processor.h"
- #include "opentelemetry/trace/span_context.h"
- #include "opentelemetry/trace/span_id.h"
- #include "opentelemetry/trace/span_metadata.h"
- #include "opentelemetry/trace/trace_flags.h"
- #include "opentelemetry/trace/trace_id.h"
- #include "opentelemetry/trace/trace_state.h"
- #include "ostream_capture.h"
- 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(const 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 cerr
- const auto captured = WithOStreamCapture(std::cerr, [&]() {
- 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);
- }
|