ostream_span_test.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include <gtest/gtest.h>
  4. #include <stdint.h>
  5. #include <array>
  6. #include <chrono>
  7. #include <initializer_list>
  8. #include <iostream>
  9. #include <sstream>
  10. #include <string>
  11. #include <utility>
  12. #include "opentelemetry/common/attribute_value.h"
  13. #include "opentelemetry/common/key_value_iterable_view.h"
  14. #include "opentelemetry/common/timestamp.h"
  15. #include "opentelemetry/exporters/ostream/span_exporter.h"
  16. #include "opentelemetry/nostd/shared_ptr.h"
  17. #include "opentelemetry/nostd/span.h"
  18. #include "opentelemetry/nostd/string_view.h"
  19. #include "opentelemetry/sdk/resource/resource.h"
  20. #include "opentelemetry/sdk/trace/exporter.h"
  21. #include "opentelemetry/sdk/trace/processor.h"
  22. #include "opentelemetry/sdk/trace/recordable.h"
  23. #include "opentelemetry/sdk/trace/simple_processor.h"
  24. #include "opentelemetry/trace/span_context.h"
  25. #include "opentelemetry/trace/span_id.h"
  26. #include "opentelemetry/trace/span_metadata.h"
  27. #include "opentelemetry/trace/trace_flags.h"
  28. #include "opentelemetry/trace/trace_id.h"
  29. #include "opentelemetry/trace/trace_state.h"
  30. #include "ostream_capture.h"
  31. using namespace opentelemetry::exporter::ostream::test;
  32. namespace trace = opentelemetry::trace;
  33. namespace common = opentelemetry::common;
  34. namespace nostd = opentelemetry::nostd;
  35. namespace trace_sdk = opentelemetry::sdk::trace;
  36. namespace resource = opentelemetry::sdk::resource;
  37. namespace exportertrace = opentelemetry::exporter::trace;
  38. using Attributes = std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>;
  39. class TestResource : public resource::Resource
  40. {
  41. public:
  42. TestResource(const resource::ResourceAttributes &attributes = resource::ResourceAttributes())
  43. : resource::Resource(attributes)
  44. {}
  45. };
  46. // Testing Shutdown functionality of OStreamSpanExporter, should expect no data to be sent to Stream
  47. TEST(OStreamSpanExporter, Shutdown)
  48. {
  49. auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter);
  50. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  51. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  52. auto recordable = processor->MakeRecordable();
  53. recordable->SetName("Test Span");
  54. // Capture the output of cerr
  55. const auto captured = WithOStreamCapture(std::cerr, [&]() {
  56. EXPECT_TRUE(processor->Shutdown());
  57. processor->OnEnd(std::move(recordable));
  58. });
  59. std::string err_message =
  60. "[Ostream Trace Exporter] Exporting 1 span(s) failed, exporter is shutdown";
  61. EXPECT_TRUE(captured.find(err_message) != std::string::npos);
  62. }
  63. constexpr const char *kDefaultSpanPrinted =
  64. "{\n"
  65. " name : \n"
  66. " trace_id : 00000000000000000000000000000000\n"
  67. " span_id : 0000000000000000\n"
  68. " tracestate : \n"
  69. " parent_span_id: 0000000000000000\n"
  70. " start : 0\n"
  71. " duration : 0\n"
  72. " description : \n"
  73. " span kind : Internal\n"
  74. " status : Unset\n"
  75. " attributes : \n"
  76. " events : \n"
  77. " links : \n"
  78. " resources : \n"
  79. " instr-lib : unknown_service\n"
  80. "}\n";
  81. // Testing what a default span that is not changed will print out, either all 0's or empty values
  82. TEST(OStreamSpanExporter, PrintDefaultSpan)
  83. {
  84. std::stringstream output;
  85. auto exporter =
  86. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  87. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  88. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  89. auto recordable = processor->MakeRecordable();
  90. processor->OnEnd(std::move(recordable));
  91. EXPECT_EQ(output.str(), kDefaultSpanPrinted);
  92. }
  93. TEST(OStreamSpanExporter, PrintSpanWithBasicFields)
  94. {
  95. std::stringstream output;
  96. auto exporter =
  97. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  98. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  99. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  100. auto recordable = processor->MakeRecordable();
  101. constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
  102. constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8};
  103. constexpr uint8_t parent_span_id_buf[] = {8, 7, 6, 5, 4, 3, 2, 1};
  104. trace::TraceId trace_id{trace_id_buf};
  105. trace::SpanId span_id{span_id_buf};
  106. trace::SpanId parent_span_id{parent_span_id_buf};
  107. const auto trace_state = trace::TraceState::GetDefault()->Set("state1", "value");
  108. const trace::SpanContext span_context{
  109. trace_id, span_id, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true, trace_state};
  110. recordable->SetIdentity(span_context, parent_span_id);
  111. recordable->SetName("Test Span");
  112. common::SystemTimestamp now(std::chrono::system_clock::now());
  113. recordable->SetStartTime(now);
  114. recordable->SetDuration(std::chrono::nanoseconds(100));
  115. recordable->SetStatus(trace::StatusCode::kOk, "Test Description");
  116. recordable->SetSpanKind(trace::SpanKind::kClient);
  117. TestResource resource1(resource::ResourceAttributes({{"key1", "val1"}}));
  118. recordable->SetResource(resource1);
  119. processor->OnEnd(std::move(recordable));
  120. std::string start = std::to_string(now.time_since_epoch().count());
  121. std::string expectedOutput =
  122. "{\n"
  123. " name : Test Span\n"
  124. " trace_id : 01020304050607080102030405060708\n"
  125. " span_id : 0102030405060708\n"
  126. " tracestate : state1=value\n"
  127. " parent_span_id: 0807060504030201\n"
  128. " start : " +
  129. start +
  130. "\n"
  131. " duration : 100\n"
  132. " description : Test Description\n"
  133. " span kind : Client\n"
  134. " status : Ok\n"
  135. " attributes : \n"
  136. " events : \n"
  137. " links : \n"
  138. " resources : \n"
  139. "\tkey1: val1\n"
  140. " instr-lib : unknown_service\n"
  141. "}\n";
  142. EXPECT_EQ(output.str(), expectedOutput);
  143. }
  144. TEST(OStreamSpanExporter, PrintSpanWithAttribute)
  145. {
  146. std::stringstream output;
  147. auto exporter =
  148. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  149. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  150. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  151. auto recordable = processor->MakeRecordable();
  152. recordable->SetAttribute("attr1", "string");
  153. processor->OnEnd(std::move(recordable));
  154. std::string expectedOutput =
  155. "{\n"
  156. " name : \n"
  157. " trace_id : 00000000000000000000000000000000\n"
  158. " span_id : 0000000000000000\n"
  159. " tracestate : \n"
  160. " parent_span_id: 0000000000000000\n"
  161. " start : 0\n"
  162. " duration : 0\n"
  163. " description : \n"
  164. " span kind : Internal\n"
  165. " status : Unset\n"
  166. " attributes : \n"
  167. "\tattr1: string\n"
  168. " events : \n"
  169. " links : \n"
  170. " resources : \n"
  171. " instr-lib : unknown_service\n"
  172. "}\n";
  173. EXPECT_EQ(output.str(), expectedOutput);
  174. }
  175. TEST(OStreamSpanExporter, PrintSpanWithArrayAttribute)
  176. {
  177. std::stringstream output;
  178. auto exporter =
  179. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  180. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  181. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  182. auto recordable = processor->MakeRecordable();
  183. std::array<int, 3> array1 = {1, 2, 3};
  184. nostd::span<int> span1{array1.data(), array1.size()};
  185. recordable->SetAttribute("array1", span1);
  186. processor->OnEnd(std::move(recordable));
  187. std::string expectedOutput =
  188. "{\n"
  189. " name : \n"
  190. " trace_id : 00000000000000000000000000000000\n"
  191. " span_id : 0000000000000000\n"
  192. " tracestate : \n"
  193. " parent_span_id: 0000000000000000\n"
  194. " start : 0\n"
  195. " duration : 0\n"
  196. " description : \n"
  197. " span kind : Internal\n"
  198. " status : Unset\n"
  199. " attributes : \n"
  200. "\tarray1: [1,2,3]\n"
  201. " events : \n"
  202. " links : \n"
  203. " resources : \n"
  204. " instr-lib : unknown_service\n"
  205. "}\n";
  206. EXPECT_EQ(output.str(), expectedOutput);
  207. }
  208. TEST(OStreamSpanExporter, PrintSpanWithEvents)
  209. {
  210. std::stringstream output;
  211. auto exporter =
  212. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  213. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  214. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  215. auto recordable = processor->MakeRecordable();
  216. common::SystemTimestamp now(std::chrono::system_clock::now());
  217. common::SystemTimestamp next(std::chrono::system_clock::now() + std::chrono::seconds(1));
  218. std::string now_str = std::to_string(now.time_since_epoch().count());
  219. std::string next_str = std::to_string(next.time_since_epoch().count());
  220. recordable->AddEvent("hello", now);
  221. recordable->AddEvent("world", next,
  222. common::KeyValueIterableView<Attributes>({{"attr1", "string"}}));
  223. processor->OnEnd(std::move(recordable));
  224. std::string expectedOutput =
  225. "{\n"
  226. " name : \n"
  227. " trace_id : 00000000000000000000000000000000\n"
  228. " span_id : 0000000000000000\n"
  229. " tracestate : \n"
  230. " parent_span_id: 0000000000000000\n"
  231. " start : 0\n"
  232. " duration : 0\n"
  233. " description : \n"
  234. " span kind : Internal\n"
  235. " status : Unset\n"
  236. " attributes : \n"
  237. " events : \n"
  238. "\t{\n"
  239. "\t name : hello\n"
  240. "\t timestamp : " +
  241. now_str +
  242. "\n"
  243. "\t attributes : \n"
  244. "\t}\n"
  245. "\t{\n"
  246. "\t name : world\n"
  247. "\t timestamp : " +
  248. next_str +
  249. "\n"
  250. "\t attributes : \n"
  251. "\t\tattr1: string\n"
  252. "\t}\n"
  253. " links : \n"
  254. " resources : \n"
  255. " instr-lib : unknown_service\n"
  256. "}\n";
  257. EXPECT_EQ(output.str(), expectedOutput);
  258. }
  259. TEST(OStreamSpanExporter, PrintSpanWithLinks)
  260. {
  261. std::stringstream output;
  262. auto exporter =
  263. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(output));
  264. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  265. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  266. auto recordable = processor->MakeRecordable();
  267. // produce valid SpanContext with pseudo span and trace Id.
  268. uint8_t span_id_buf[trace::SpanId::kSize] = {
  269. 1,
  270. };
  271. trace::SpanId span_id{span_id_buf};
  272. uint8_t trace_id_buf[trace::TraceId::kSize] = {
  273. 2,
  274. };
  275. trace::TraceId trace_id{trace_id_buf};
  276. const auto span_context =
  277. trace::SpanContext(trace_id, span_id, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true);
  278. // and another to check preserving order.
  279. uint8_t span_id_buf2[trace::SpanId::kSize] = {
  280. 3,
  281. };
  282. trace::SpanId span_id2{span_id_buf2};
  283. const auto span_context2 =
  284. trace::SpanContext(trace_id, span_id2, trace::TraceFlags{trace::TraceFlags::kIsSampled}, true,
  285. trace::TraceState::FromHeader("state1=value"));
  286. recordable->AddLink(span_context);
  287. recordable->AddLink(span_context2,
  288. common::KeyValueIterableView<Attributes>({{"attr1", "string"}}));
  289. processor->OnEnd(std::move(recordable));
  290. std::string expectedOutput =
  291. "{\n"
  292. " name : \n"
  293. " trace_id : 00000000000000000000000000000000\n"
  294. " span_id : 0000000000000000\n"
  295. " tracestate : \n"
  296. " parent_span_id: 0000000000000000\n"
  297. " start : 0\n"
  298. " duration : 0\n"
  299. " description : \n"
  300. " span kind : Internal\n"
  301. " status : Unset\n"
  302. " attributes : \n"
  303. " events : \n"
  304. " links : \n"
  305. "\t{\n"
  306. "\t trace_id : 02000000000000000000000000000000\n"
  307. "\t span_id : 0100000000000000\n"
  308. "\t tracestate : \n"
  309. "\t attributes : \n"
  310. "\t}\n"
  311. "\t{\n"
  312. "\t trace_id : 02000000000000000000000000000000\n"
  313. "\t span_id : 0300000000000000\n"
  314. "\t tracestate : state1=value\n"
  315. "\t attributes : \n"
  316. "\t\tattr1: string\n"
  317. "\t}\n"
  318. " resources : \n"
  319. " instr-lib : unknown_service\n"
  320. "}\n";
  321. EXPECT_EQ(output.str(), expectedOutput);
  322. }
  323. // Test with the three common ostreams, tests are more of a sanity check and usage examples.
  324. TEST(OStreamSpanExporter, PrintSpanToCout)
  325. {
  326. auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter);
  327. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  328. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  329. auto recordable = processor->MakeRecordable();
  330. const auto captured =
  331. WithOStreamCapture(std::cout, [&]() { processor->OnEnd(std::move(recordable)); });
  332. EXPECT_EQ(captured, kDefaultSpanPrinted);
  333. }
  334. TEST(OStreamSpanExporter, PrintSpanToCerr)
  335. {
  336. auto exporter =
  337. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(std::cerr));
  338. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  339. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  340. auto recordable = processor->MakeRecordable();
  341. const auto captured =
  342. WithOStreamCapture(std::cerr, [&]() { processor->OnEnd(std::move(recordable)); });
  343. EXPECT_EQ(captured, kDefaultSpanPrinted);
  344. }
  345. TEST(OStreamSpanExporter, PrintSpanToClog)
  346. {
  347. auto exporter =
  348. std::unique_ptr<trace_sdk::SpanExporter>(new exportertrace::OStreamSpanExporter(std::clog));
  349. auto processor = std::shared_ptr<trace_sdk::SpanProcessor>(
  350. new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  351. auto recordable = processor->MakeRecordable();
  352. const auto captured =
  353. WithOStreamCapture(std::clog, [&]() { processor->OnEnd(std::move(recordable)); });
  354. EXPECT_EQ(captured, kDefaultSpanPrinted);
  355. }