ostream_log_test.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include <gtest/gtest.h>
  4. #include <array>
  5. #include <chrono>
  6. #include <initializer_list>
  7. #include <iostream>
  8. #include <sstream>
  9. #include <string>
  10. #include <utility>
  11. #include <vector>
  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/log_record_exporter.h"
  16. #include "opentelemetry/exporters/ostream/log_record_exporter_factory.h"
  17. #include "opentelemetry/logs/event_id.h"
  18. #include "opentelemetry/logs/logger.h"
  19. #include "opentelemetry/logs/logger_provider.h"
  20. #include "opentelemetry/logs/provider.h"
  21. #include "opentelemetry/logs/severity.h"
  22. #include "opentelemetry/nostd/shared_ptr.h"
  23. #include "opentelemetry/nostd/span.h"
  24. #include "opentelemetry/nostd/string_view.h"
  25. #include "opentelemetry/nostd/utility.h"
  26. #include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
  27. #include "opentelemetry/sdk/logs/exporter.h"
  28. #include "opentelemetry/sdk/logs/logger_provider.h"
  29. #include "opentelemetry/sdk/logs/processor.h"
  30. #include "opentelemetry/sdk/logs/provider.h"
  31. #include "opentelemetry/sdk/logs/read_write_log_record.h"
  32. #include "opentelemetry/sdk/logs/readable_log_record.h"
  33. #include "opentelemetry/sdk/logs/recordable.h"
  34. #include "opentelemetry/sdk/logs/simple_log_record_processor.h"
  35. #include "opentelemetry/sdk/resource/resource.h"
  36. #include "opentelemetry/sdk/version/version.h"
  37. #include "opentelemetry/version.h"
  38. namespace sdklogs = opentelemetry::sdk::logs;
  39. namespace logs_api = opentelemetry::logs;
  40. namespace nostd = opentelemetry::nostd;
  41. namespace exporterlogs = opentelemetry::exporter::logs;
  42. namespace common = opentelemetry::common;
  43. using Attributes = std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>;
  44. OPENTELEMETRY_BEGIN_NAMESPACE
  45. namespace exporter
  46. {
  47. namespace logs
  48. {
  49. namespace
  50. {
  51. static opentelemetry::sdk::instrumentationscope::InstrumentationScope GetTestInstrumentationScope()
  52. {
  53. opentelemetry::sdk::instrumentationscope::InstrumentationScope result =
  54. opentelemetry::sdk::logs::ReadableLogRecord::GetDefaultInstrumentationScope();
  55. result.SetAttribute("scope.attr.key", "scope.attr.value");
  56. return result;
  57. }
  58. } // namespace
  59. // Test that when OStream Log exporter is shutdown, no logs should be sent to stream
  60. TEST(OStreamLogRecordExporter, Shutdown)
  61. {
  62. auto exporter =
  63. std::unique_ptr<sdklogs::LogRecordExporter>(new exporterlogs::OStreamLogRecordExporter);
  64. // Save cerr original buffer here
  65. std::streambuf *original = std::cerr.rdbuf();
  66. // Redirect cerr to our stringstream buffer
  67. std::stringstream output;
  68. std::cerr.rdbuf(output.rdbuf());
  69. EXPECT_TRUE(exporter->Shutdown());
  70. // After processor/exporter is shutdown, no logs should be sent to stream
  71. auto record = exporter->MakeRecordable();
  72. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetBody("Log record not empty");
  73. exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1));
  74. // Restore original stringstream buffer
  75. std::cerr.rdbuf(original);
  76. std::string err_message =
  77. "[Ostream Log Exporter] Exporting 1 log(s) failed, exporter is shutdown";
  78. EXPECT_TRUE(output.str().find(err_message) != std::string::npos);
  79. }
  80. // ---------------------------------- Print to cout -------------------------
  81. // Testing what a default log record that has no values changed will print out
  82. // This function tests MakeRecordable() as well as Export().
  83. TEST(OstreamLogExporter, DefaultLogRecordToCout)
  84. {
  85. auto exporter = std::unique_ptr<sdklogs::LogRecordExporter>(
  86. new exporterlogs::OStreamLogRecordExporter(std::cout));
  87. // Save cout's original buffer here
  88. std::streambuf *original = std::cout.rdbuf();
  89. // Redirect cout to our stringstream buffer
  90. std::stringstream output;
  91. std::cout.rdbuf(output.rdbuf());
  92. // Pass a default recordable created by the exporter to be exported
  93. auto log_record = exporter->MakeRecordable();
  94. opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope =
  95. GetTestInstrumentationScope();
  96. log_record->SetInstrumentationScope(instrumentation_scope);
  97. exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&log_record, 1));
  98. // Restore cout's original stringstream
  99. std::cout.rdbuf(original);
  100. std::vector<std::string> expected_output{
  101. "{\n",
  102. " timestamp : 0\n",
  103. " severity_num : 0\n",
  104. " severity_text : INVALID\n",
  105. " body : \n",
  106. " resource : \n",
  107. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  108. " telemetry.sdk.name: opentelemetry\n",
  109. " telemetry.sdk.language: cpp\n",
  110. " attributes : \n",
  111. " event_id : 0\n",
  112. " event_name : \n",
  113. " trace_id : 00000000000000000000000000000000\n",
  114. " span_id : 0000000000000000\n",
  115. " trace_flags : 00\n",
  116. " scope : \n",
  117. " name : otel-cpp\n",
  118. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  119. " schema_url : https://opentelemetry.io/schemas/1.15.0\n",
  120. " attributes : \n",
  121. " scope.attr.key: scope.attr.value\n",
  122. "}\n"};
  123. std::string ostream_output = output.str();
  124. for (auto &expected : expected_output)
  125. {
  126. std::string::size_type result = ostream_output.find(expected);
  127. if (result == std::string::npos)
  128. {
  129. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  130. }
  131. ASSERT_NE(result, std::string::npos);
  132. }
  133. }
  134. // Testing what a log record with only the "timestamp", "severity", "name" and "message" fields set,
  135. // will print out
  136. TEST(OStreamLogRecordExporter, SimpleLogToCout)
  137. {
  138. // Initialize an Ostream exporter to std::cout
  139. auto exporter = std::unique_ptr<sdklogs::LogRecordExporter>(
  140. new exporterlogs::OStreamLogRecordExporter(std::cout));
  141. // Save original stream buffer, then redirect cout to our new stream buffer
  142. std::streambuf *original = std::cout.rdbuf();
  143. std::stringstream output;
  144. std::cout.rdbuf(output.rdbuf());
  145. // Pass a default recordable created by the exporter to be exported
  146. // Create a log record and manually timestamp, severity, name, message
  147. common::SystemTimestamp now(std::chrono::system_clock::now());
  148. auto record = std::unique_ptr<sdklogs::Recordable>(new sdklogs::ReadWriteLogRecord());
  149. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetTimestamp(now);
  150. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetObservedTimestamp(now);
  151. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())
  152. ->SetSeverity(logs_api::Severity::kTrace); // kTrace has enum value of 1
  153. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetBody("Message");
  154. opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope =
  155. GetTestInstrumentationScope();
  156. record->SetInstrumentationScope(instrumentation_scope);
  157. // Log a record to cout
  158. exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1));
  159. // Reset cout's original stringstream buffer
  160. std::cout.rdbuf(original);
  161. std::vector<std::string> expected_output{
  162. "{\n",
  163. " timestamp : " + std::to_string(now.time_since_epoch().count()) +
  164. "\n"
  165. " observed_timestamp : " +
  166. std::to_string(now.time_since_epoch().count()) +
  167. "\n"
  168. " severity_num : 1\n"
  169. " severity_text : TRACE\n"
  170. " body : Message\n",
  171. " resource : \n",
  172. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  173. " telemetry.sdk.name: opentelemetry\n",
  174. " telemetry.sdk.language: cpp\n",
  175. " attributes : \n",
  176. " event_id : 0\n",
  177. " event_name : \n",
  178. " trace_id : 00000000000000000000000000000000\n",
  179. " span_id : 0000000000000000\n",
  180. " trace_flags : 00\n",
  181. " scope : \n",
  182. " name : otel-cpp\n",
  183. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  184. " schema_url : https://opentelemetry.io/schemas/1.15.0\n",
  185. " attributes : \n",
  186. " scope.attr.key: scope.attr.value\n",
  187. "}\n"};
  188. std::string ostream_output = output.str();
  189. for (auto &expected : expected_output)
  190. {
  191. std::string::size_type result = ostream_output.find(expected);
  192. if (result == std::string::npos)
  193. {
  194. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  195. }
  196. ASSERT_NE(result, std::string::npos);
  197. }
  198. }
  199. // ---------------------------------- Print to cerr --------------------------
  200. // Testing what a log record with only the "resource" and "attributes" fields
  201. // (i.e. KeyValueIterable types) set with primitive types, will print out
  202. TEST(OStreamLogRecordExporter, LogWithStringAttributesToCerr)
  203. {
  204. // Initialize an Ostream exporter to cerr
  205. auto exporter = std::unique_ptr<sdklogs::LogRecordExporter>(
  206. new exporterlogs::OStreamLogRecordExporter(std::cerr));
  207. // Save original stream buffer, then redirect cout to our new stream buffer
  208. std::streambuf *original = std::cerr.rdbuf();
  209. std::stringstream stdcerrOutput;
  210. std::cerr.rdbuf(stdcerrOutput.rdbuf());
  211. // Pass a recordable created by the exporter to be exported
  212. auto record = exporter->MakeRecordable();
  213. // Set resources for this log record only of type <string, string>
  214. auto resource = opentelemetry::sdk::resource::Resource::Create({{"key1", "val1"}});
  215. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetResource(resource);
  216. // Set attributes to this log record of type <string, AttributeValue>
  217. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetAttribute("a", true);
  218. opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope =
  219. GetTestInstrumentationScope();
  220. record->SetInstrumentationScope(instrumentation_scope);
  221. // Log record to cerr
  222. exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1));
  223. // Reset cerr's original stringstream buffer
  224. std::cerr.rdbuf(original);
  225. std::vector<std::string> expected_output{
  226. "{\n",
  227. " timestamp : 0\n",
  228. " severity_num : 0\n",
  229. " severity_text : INVALID\n",
  230. " body : \n",
  231. " resource : \n",
  232. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  233. " telemetry.sdk.name: opentelemetry\n",
  234. " telemetry.sdk.language: cpp\n",
  235. " service.name: unknown_service\n",
  236. " key1: val1\n",
  237. " attributes : \n",
  238. " a: 1\n",
  239. " event_id : 0\n",
  240. " event_name : \n",
  241. " trace_id : 00000000000000000000000000000000\n",
  242. " span_id : 0000000000000000\n",
  243. " trace_flags : 00\n",
  244. " scope : \n",
  245. " name : otel-cpp\n",
  246. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  247. " schema_url : https://opentelemetry.io/schemas/1.15.0\n",
  248. " attributes : \n",
  249. " scope.attr.key: scope.attr.value\n",
  250. "}\n"};
  251. std::string ostream_output = stdcerrOutput.str();
  252. for (auto &expected : expected_output)
  253. {
  254. std::string::size_type result = ostream_output.find(expected);
  255. if (result == std::string::npos)
  256. {
  257. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  258. }
  259. ASSERT_NE(result, std::string::npos);
  260. }
  261. }
  262. // ---------------------------------- Print to clog -------------------------
  263. // Testing what a log record with only the "resource", and "attributes" fields
  264. // (i.e. KeyValueIterable types), set with 2D arrays as values, will print out
  265. TEST(OStreamLogRecordExporter, LogWithVariantTypesToClog)
  266. {
  267. // Initialize an Ostream exporter to cerr
  268. auto exporter = std::unique_ptr<sdklogs::LogRecordExporter>(
  269. new exporterlogs::OStreamLogRecordExporter(std::clog));
  270. // Save original stream buffer, then redirect cout to our new stream buffer
  271. std::streambuf *original = std::clog.rdbuf();
  272. std::stringstream stdclogOutput;
  273. std::clog.rdbuf(stdclogOutput.rdbuf());
  274. // Pass a recordable created by the exporter to be exported
  275. auto record = exporter->MakeRecordable();
  276. // Set resources for this log record of only integer types as the value
  277. std::array<int, 3> array1 = {1, 2, 3};
  278. nostd::span<int> data1{array1.data(), array1.size()};
  279. auto resource = opentelemetry::sdk::resource::Resource::Create({{"res1", data1}});
  280. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())->SetResource(resource);
  281. // Set resources for this log record of bool types as the value
  282. // e.g. key/value is a par of type <string, array of bools>
  283. std::array<bool, 3> array = {false, true, false};
  284. static_cast<sdklogs::ReadWriteLogRecord *>(record.get())
  285. ->SetAttribute("attr1", nostd::span<bool>{array.data(), array.size()});
  286. opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope =
  287. GetTestInstrumentationScope();
  288. record->SetInstrumentationScope(instrumentation_scope);
  289. // Log a record to clog
  290. exporter->Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1));
  291. // Reset clog's original stringstream buffer
  292. std::clog.rdbuf(original);
  293. std::vector<std::string> expected_output{
  294. "{\n",
  295. " timestamp : 0\n",
  296. " severity_num : 0\n",
  297. " severity_text : INVALID\n",
  298. " body : \n",
  299. " resource : \n",
  300. " service.name: unknown_service\n",
  301. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  302. " telemetry.sdk.name: opentelemetry\n",
  303. " telemetry.sdk.language: cpp\n",
  304. " res1: [1,2,3]\n",
  305. " attributes : \n",
  306. " attr1: [0,1,0]\n",
  307. " event_id : 0\n",
  308. " event_name : \n",
  309. " trace_id : 00000000000000000000000000000000\n",
  310. " span_id : 0000000000000000\n",
  311. " trace_flags : 00\n",
  312. " scope : \n",
  313. " name : otel-cpp\n",
  314. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  315. " schema_url : https://opentelemetry.io/schemas/1.15.0\n",
  316. " attributes : \n",
  317. " scope.attr.key: scope.attr.value\n",
  318. "}\n"};
  319. std::string ostream_output = stdclogOutput.str();
  320. for (auto &expected : expected_output)
  321. {
  322. std::string::size_type result = ostream_output.find(expected);
  323. if (result == std::string::npos)
  324. {
  325. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  326. }
  327. ASSERT_NE(result, std::string::npos);
  328. }
  329. }
  330. // // ---------------------------------- Integration Tests -------------------------
  331. // Test using the simple log processor and ostream exporter to cout
  332. // and use the rest of the logging pipeline (Logger, LoggerProvider, Provider) as well
  333. TEST(OStreamLogRecordExporter, IntegrationTest)
  334. {
  335. // Initialize a logger
  336. auto exporter =
  337. std::unique_ptr<sdklogs::LogRecordExporter>(new exporterlogs::OStreamLogRecordExporter);
  338. auto sdkProvider = std::shared_ptr<sdklogs::LoggerProvider>(new sdklogs::LoggerProvider());
  339. sdkProvider->AddProcessor(std::unique_ptr<sdklogs::LogRecordProcessor>(
  340. new sdklogs::SimpleLogRecordProcessor(std::move(exporter))));
  341. auto apiProvider = nostd::shared_ptr<logs_api::LoggerProvider>(sdkProvider);
  342. auto provider = nostd::shared_ptr<logs_api::LoggerProvider>(apiProvider);
  343. sdklogs::Provider::SetLoggerProvider(provider);
  344. const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"};
  345. auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger(
  346. "Logger", "opentelelemtry_library", OPENTELEMETRY_SDK_VERSION, schema_url,
  347. {{"scope.attr.key", 123}});
  348. // Back up cout's streambuf
  349. std::streambuf *original = std::cout.rdbuf();
  350. // Redirect cout to our string stream
  351. std::stringstream stdcoutOutput;
  352. std::cout.rdbuf(stdcoutOutput.rdbuf());
  353. // Write a log to ostream exporter
  354. common::SystemTimestamp now(std::chrono::system_clock::now());
  355. logger->EmitLogRecord(logs_api::Severity::kDebug, "Hello", now);
  356. // Restore cout's original streambuf
  357. std::cout.rdbuf(original);
  358. // Compare actual vs expected outputs
  359. std::vector<std::string> expected_output{
  360. "{\n",
  361. " timestamp : " + std::to_string(now.time_since_epoch().count()) + "\n",
  362. " severity_num : 5\n",
  363. " severity_text : DEBUG\n",
  364. " body : Hello\n",
  365. " resource : \n",
  366. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  367. " service.name: unknown_service\n",
  368. " telemetry.sdk.name: opentelemetry\n",
  369. " telemetry.sdk.language: cpp\n",
  370. " attributes : \n",
  371. " event_id : 0\n",
  372. " event_name : \n",
  373. " trace_id : 00000000000000000000000000000000\n",
  374. " span_id : 0000000000000000\n",
  375. " trace_flags : 00\n",
  376. " scope : \n",
  377. " name : opentelelemtry_library\n",
  378. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  379. " schema_url : https://opentelemetry.io/schemas/1.11.0\n",
  380. " attributes : \n",
  381. " scope.attr.key: 123\n",
  382. "}\n"};
  383. std::string ostream_output = stdcoutOutput.str();
  384. for (auto &expected : expected_output)
  385. {
  386. std::string::size_type result = ostream_output.find(expected);
  387. if (result == std::string::npos)
  388. {
  389. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  390. }
  391. ASSERT_NE(result, std::string::npos);
  392. }
  393. }
  394. // Test using the simple log processor and ostream exporter to cout
  395. // and use the rest of the logging pipeline (Logger, LoggerProvider, Provider) and user-facing API
  396. // as well
  397. TEST(OStreamLogRecordExporter, IntegrationTestWithEventId)
  398. {
  399. // Initialize a logger
  400. auto exporter =
  401. std::unique_ptr<sdklogs::LogRecordExporter>(new exporterlogs::OStreamLogRecordExporter);
  402. auto sdkProvider = std::shared_ptr<sdklogs::LoggerProvider>(new sdklogs::LoggerProvider());
  403. sdkProvider->AddProcessor(std::unique_ptr<sdklogs::LogRecordProcessor>(
  404. new sdklogs::SimpleLogRecordProcessor(std::move(exporter))));
  405. auto apiProvider = nostd::shared_ptr<logs_api::LoggerProvider>(sdkProvider);
  406. auto provider = nostd::shared_ptr<logs_api::LoggerProvider>(apiProvider);
  407. sdklogs::Provider::SetLoggerProvider(provider);
  408. const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"};
  409. auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger(
  410. "Logger", "opentelelemtry_library", OPENTELEMETRY_SDK_VERSION, schema_url,
  411. {{"scope.attr.key", 123}});
  412. // Back up cout's streambuf
  413. std::streambuf *original = std::cout.rdbuf();
  414. // Redirect cout to our string stream
  415. std::stringstream stdcoutOutput;
  416. std::cout.rdbuf(stdcoutOutput.rdbuf());
  417. logs_api::EventId event_id{12345678, "test_event_id"};
  418. // Write a log to ostream exporter
  419. logger->Debug(event_id, "Hello {key1} {key2}",
  420. common::MakeKeyValueIterableView<Attributes>({{"key1", 123}, {"key2", "value2"}}));
  421. // Restore cout's original streambuf
  422. std::cout.rdbuf(original);
  423. // Compare actual vs expected outputs
  424. std::vector<std::string> expected_output{
  425. " severity_num : 5\n",
  426. " severity_text : DEBUG\n",
  427. " body : Hello {key1} {key2}\n",
  428. " resource : \n",
  429. " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n",
  430. " service.name: unknown_service\n",
  431. " telemetry.sdk.name: opentelemetry\n",
  432. " telemetry.sdk.language: cpp\n",
  433. " attributes : \n",
  434. " event_id : 12345678\n",
  435. " event_name : test_event_id\n",
  436. " trace_id : 00000000000000000000000000000000\n",
  437. " span_id : 0000000000000000\n",
  438. " trace_flags : 00\n",
  439. " scope : \n",
  440. " name : opentelelemtry_library\n",
  441. " version : " OPENTELEMETRY_SDK_VERSION "\n",
  442. " schema_url : https://opentelemetry.io/schemas/1.11.0\n",
  443. " attributes : \n",
  444. " scope.attr.key: 123\n",
  445. "}\n"};
  446. std::string ostream_output = stdcoutOutput.str();
  447. for (auto &expected : expected_output)
  448. {
  449. std::string::size_type result = ostream_output.find(expected);
  450. if (result == std::string::npos)
  451. {
  452. std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << '\n';
  453. }
  454. ASSERT_NE(result, std::string::npos);
  455. }
  456. }
  457. // Test using the factory to create the ostream exporter
  458. TEST(OStreamLogRecordExporter, Factory)
  459. {
  460. auto exporter = OStreamLogRecordExporterFactory::Create();
  461. ASSERT_NE(exporter, nullptr);
  462. }
  463. } // namespace logs
  464. } // namespace exporter
  465. OPENTELEMETRY_END_NAMESPACE