|
8 | 8 | #include <cstdint> |
9 | 9 | #include <functional> |
10 | 10 | #include <future> |
| 11 | +#include <memory> // IWYU pragma: keep |
11 | 12 | #include <mutex> |
12 | 13 | #include <stdexcept> |
13 | 14 | #include <string> |
|
29 | 30 | #include "opentelemetry/nostd/utility.h" |
30 | 31 | #include "opentelemetry/nostd/variant.h" |
31 | 32 | #include "opentelemetry/sdk/common/exporter_utils.h" |
| 33 | +#include "opentelemetry/sdk/common/global_log_handler.h" |
32 | 34 | #include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h" |
33 | 35 | #include "opentelemetry/sdk/instrumentationscope/scope_configurator.h" |
34 | 36 | #include "opentelemetry/sdk/logs/event_logger_provider.h" // IWYU pragma: keep |
|
44 | 46 | #include "opentelemetry/sdk/logs/recordable.h" |
45 | 47 | #include "opentelemetry/sdk/logs/simple_log_record_processor.h" |
46 | 48 | #include "opentelemetry/sdk/resource/resource.h" |
| 49 | +#include "opentelemetry/test_common/sdk/common/scoped_test_log_handler.h" |
47 | 50 |
|
48 | 51 | using namespace opentelemetry::sdk::logs; |
49 | 52 | namespace logs_api = opentelemetry::logs; |
@@ -679,6 +682,61 @@ TEST(LoggerProviderSDK, ConstructorsAreNotNoexcept) |
679 | 682 | } |
680 | 683 |
|
681 | 684 | #if OPENTELEMETRY_HAVE_EXCEPTIONS |
| 685 | +TEST(LoggerProviderSDK, ConstructionFailureDiagnosticsAllowProviderReentry) |
| 686 | +{ |
| 687 | + using opentelemetry::sdk::common::internal_log::LogLevel; |
| 688 | + using opentelemetry::test_common::ScopedTestLogHandler; |
| 689 | + for (int exception_type = 0; exception_type < 2; ++exception_type) |
| 690 | + { |
| 691 | + SCOPED_TRACE(exception_type); |
| 692 | + int construct_attempts = 0; |
| 693 | + auto configurator = std::make_unique<scope_sdk::ScopeConfigurator<LoggerConfig>>( |
| 694 | + scope_sdk::ScopeConfigurator<LoggerConfig>::Builder(LoggerConfig::Default()) |
| 695 | + .AddCondition( |
| 696 | + [&](const scope_sdk::InstrumentationScope &scope) { |
| 697 | + ++construct_attempts; |
| 698 | + if (scope.GetName() == "throwing-scope") |
| 699 | + { |
| 700 | + if (exception_type == 0) |
| 701 | + { |
| 702 | + throw std::runtime_error("injected construction failure"); |
| 703 | + } |
| 704 | + throw 1; |
| 705 | + } |
| 706 | + return false; |
| 707 | + }, |
| 708 | + LoggerConfig::Default()) |
| 709 | + .Build()); |
| 710 | + LoggerProvider provider(std::vector<std::unique_ptr<LogRecordProcessor>>{}, |
| 711 | + opentelemetry::sdk::resource::Resource::Create({}), |
| 712 | + std::move(configurator)); |
| 713 | + auto cached = provider.GetLogger("cached-logger", "cached-scope"); |
| 714 | + nostd::shared_ptr<logs_api::Logger> reentrant_noop; |
| 715 | + int diagnostics = 0; |
| 716 | + ScopedTestLogHandler handler(LogLevel::Error, [&](const ScopedTestLogHandler::Entry &entry) { |
| 717 | + ++diagnostics; |
| 718 | + EXPECT_EQ(entry.level, LogLevel::Error); |
| 719 | + EXPECT_EQ(provider.GetLogger("cached-logger", "cached-scope"), cached); |
| 720 | + reentrant_noop = provider.GetLogger("uncached-logger", "uncached-scope"); |
| 721 | + }); |
| 722 | + |
| 723 | + auto failed = provider.GetLogger("throwing-logger", "throwing-scope"); |
| 724 | + ASSERT_NE(failed, nullptr); |
| 725 | + EXPECT_EQ(diagnostics, 1); |
| 726 | + EXPECT_EQ(reentrant_noop, failed); |
| 727 | + EXPECT_EQ(failed->GetName(), "noop logger"); |
| 728 | + EXPECT_EQ(provider.GetLogger("cached-logger", "cached-scope"), cached); |
| 729 | + EXPECT_EQ(provider.GetLogger("another-logger", "another-scope"), failed); |
| 730 | + EXPECT_EQ(construct_attempts, 2); |
| 731 | + EXPECT_EQ(diagnostics, 1); |
| 732 | + auto entries = handler.Drain(); |
| 733 | + ASSERT_EQ(entries.size(), 1u); |
| 734 | + EXPECT_NE(entries[0].msg.find(exception_type == 0 ? "injected construction failure" |
| 735 | + : "unknown exception"), |
| 736 | + std::string::npos); |
| 737 | + } |
| 738 | +} |
| 739 | + |
682 | 740 | TEST(LoggerProviderSDK, GetLoggerReturnsNoopOnConstructionFailure) |
683 | 741 | { |
684 | 742 | auto should_throw = std::make_shared<bool>(true); |
|
0 commit comments