Skip to content

Commit d27f4cd

Browse files
committed
test case for otel_sdk hang
1 parent 04ad125 commit d27f4cd

File tree

7 files changed

+798
-0
lines changed

7 files changed

+798
-0
lines changed

.bazelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ startup --client_debug
142142

143143
common --flag_alias=dll=@otel_sdk//:with_dll
144144

145+
# disable GRPC experiments
146+
build --define=grpc_experiments_are_final=true
147+
145148
## This is what my ../top.bazelrc contains (not in the repo as local to my machine)
146149
# build --disk_cache=f:/b/d
147150
# common --repository_cache=f:/b/r

x/hang/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cc_test(
2+
name = "hang",
3+
srcs = ["hang.cpp", "otel_sdk.cpp", "otel_api.cpp", "otel_sdk.h", "otel_api.h"],
4+
deps = ["@otel_sdk//:dll"],
5+
env = {
6+
"OTEL_LOG_LEVEL": "5",
7+
"OTEL_ENABLED": "1",
8+
}
9+
)

x/hang/hang.cpp

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#include <thread>
2+
#include <condition_variable>
3+
#include <mutex>
4+
#include <memory>
5+
#include <vector>
6+
#include <memory>
7+
8+
#pragma comment(lib,"advapi32")
9+
#include "otel_sdk.h"
10+
#include "otel_api.h"
11+
12+
#include "opentelemetry/sdk/version/version.h"
13+
14+
// api headers (logs, traces, metrics)
15+
#include "opentelemetry/logs/provider.h"
16+
#include "opentelemetry/metrics/provider.h"
17+
#include "opentelemetry/trace/provider.h"
18+
19+
// sdk providers (logs, traces, metrics)
20+
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
21+
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
22+
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
23+
24+
// sdk metric views
25+
#include "opentelemetry/sdk/metrics/view/instrument_selector_factory.h"
26+
#include "opentelemetry/sdk/metrics/view/meter_selector_factory.h"
27+
#include "opentelemetry/sdk/metrics/view/view_factory.h"
28+
29+
// sdk processors (simple logs, simple traces, periodic exporting metrics)
30+
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
31+
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h"
32+
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
33+
34+
// sdk exporter factories (logs, traces, metrics)
35+
#include "opentelemetry/exporters/ostream/log_record_exporter.h"
36+
#include "opentelemetry/exporters/ostream/metric_exporter_factory.h"
37+
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
38+
#include "opentelemetry/exporters/otlp/otlp_grpc_forward_proxy.h"
39+
#include "opentelemetry/exporters/otlp/otlp_environment.h"
40+
41+
#include <opentelemetry/metrics/provider.h>
42+
#include <opentelemetry/sdk/common/global_log_handler.h>
43+
#include <opentelemetry/sdk/common/env_variables.h>
44+
#include <opentelemetry/sdk/resource/semantic_conventions.h>
45+
#include <opentelemetry/sdk/metrics/meter_provider_factory.h>
46+
#include <opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h>
47+
#include <opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h>
48+
49+
#include <opentelemetry/version.h>
50+
#include <opentelemetry/trace/provider.h>
51+
#include <opentelemetry/logs/provider.h>
52+
#include <opentelemetry/sdk/common/global_log_handler.h>
53+
#include <opentelemetry/sdk/common/env_variables.h>
54+
#include <opentelemetry/sdk/resource/semantic_conventions.h>
55+
#include <opentelemetry/sdk/trace/tracer_provider.h>
56+
#include <opentelemetry/sdk/trace/tracer_provider_factory.h>
57+
#include <opentelemetry/sdk/trace/batch_span_processor_options.h>
58+
#include <opentelemetry/sdk/trace/batch_span_processor_factory.h>
59+
#include "opentelemetry/sdk/trace/processor.h"
60+
#include <opentelemetry/sdk/logs/logger_provider_factory.h>
61+
#include <opentelemetry/sdk/logs/batch_log_record_processor_options.h>
62+
#include <opentelemetry/sdk/logs/batch_log_record_processor_factory.h>
63+
#include <opentelemetry/sdk/logs/processor.h>
64+
#include <opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h>
65+
#include <opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h>
66+
67+
#include <opentelemetry/logs/provider.h>
68+
#include <opentelemetry/trace/provider.h>
69+
#include <opentelemetry/metrics/provider.h>
70+
71+
#include <opentelemetry/sdk/common/global_log_handler.h>
72+
#include <opentelemetry/sdk/common/env_variables.h>
73+
74+
#include <opentelemetry/sdk/resource/semantic_conventions.h>
75+
76+
#include <opentelemetry/sdk/logs/logger_provider_factory.h>
77+
#include <opentelemetry/sdk/logs/simple_log_record_processor_factory.h>
78+
#include <opentelemetry/sdk/logs/batch_log_record_processor_options.h>
79+
#include <opentelemetry/sdk/logs/batch_log_record_processor_factory.h>
80+
#include <opentelemetry/sdk/logs/processor.h>
81+
82+
#include <opentelemetry/sdk/metrics/meter_provider_factory.h>
83+
#include <opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h>
84+
#include <opentelemetry/sdk/metrics/view/instrument_selector_factory.h>
85+
#include <opentelemetry/sdk/metrics/view/meter_selector_factory.h>
86+
#include <opentelemetry/sdk/metrics/view/view_factory.h>
87+
88+
#include <opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h>
89+
#include <opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h>
90+
#include <opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h>
91+
92+
#include "opentelemetry/exporters/ostream/log_record_exporter.h"
93+
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
94+
#include "opentelemetry/exporters/ostream/metric_exporter_factory.h"
95+
96+
int main(int argc, const char* argv[])
97+
{
98+
using namespace opentelemetry;
99+
100+
otel_sdk::instance instance;
101+
if( !otel_api::enabled() )
102+
{
103+
fprintf(stderr,"FATAL: Otel not enabled\n");
104+
return 1;
105+
}
106+
{
107+
using namespace sdk::common::internal_log;
108+
GlobalLogHandler::SetLogLevel(LogLevel::Debug);
109+
}
110+
111+
int index = argc == 2 ? atoi(argv[1]) : -1;
112+
113+
setvbuf(stdout, nullptr, _IONBF,0);
114+
setvbuf(stderr, nullptr, _IONBF,0);
115+
setvbuf(stdin, nullptr, _IONBF,0);
116+
117+
//exporter::otlp::OtlpGrpcMetricExporterOptions exporterOptions;
118+
auto exporter{ exporter::otlp::OtlpGrpcMetricExporterFactory::Create( {} ) };
119+
auto stdoutExporter = exporter::metrics::OStreamMetricExporterFactory::Create();
120+
121+
// Initialize and set the global MeterProvider
122+
sdk::metrics::PeriodicExportingMetricReaderOptions options;
123+
options.export_interval_millis = std::chrono::milliseconds(500);
124+
options.export_timeout_millis = std::chrono::milliseconds(250);
125+
auto reader{ sdk::metrics::PeriodicExportingMetricReaderFactory::Create(std::move(exporter), options) };
126+
auto stdoutReader{ sdk::metrics::PeriodicExportingMetricReaderFactory::Create(std::move(stdoutExporter), options) };
127+
auto meterProvider{ sdk::metrics::MeterProviderFactory::Create() };
128+
meterProvider->AddMetricReader(std::move(reader));
129+
meterProvider->AddMetricReader(std::move(stdoutReader));
130+
metrics::Provider::SetMeterProvider(std::move(meterProvider));
131+
132+
std::unique_ptr<metrics::Counter<double>> counter;
133+
134+
auto provider = metrics::Provider::GetMeterProvider();
135+
auto meter{ provider->GetMeter("malkia_test_meter", "1.2.0") };
136+
std::vector<std::unique_ptr<metrics::Counter<double>>> counters;
137+
counters.reserve(10);
138+
for(int i=0; i<10; i++)
139+
{
140+
char buf[100];
141+
sprintf(buf,"counter_%d", i);
142+
counters.push_back( std::move( meter->CreateDoubleCounter(buf)));
143+
}
144+
for(int i=0; i<10; i++)
145+
{
146+
counters[i]->Add(1);
147+
}
148+
Sleep(1000);
149+
150+
// if( const auto sp{
151+
// std::dynamic_pointer_cast<sdk::metrics::MeterProvider>(
152+
// metrics::Provider::GetMeterProvider() ) }; sp )
153+
// {
154+
// if( const auto p{ sp.get() }; p )
155+
// {
156+
// p->ForceFlush();
157+
// p->Shutdown();
158+
// }
159+
// }
160+
// metrics::Provider::SetMeterProvider({});
161+
162+
FatalExit(0);
163+
_Exit(0);
164+
165+
return 0;
166+
}

x/hang/otel_api.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include "otel_api.h"
2+
3+
#include <windows.h>
4+
#include <cstdio>
5+
6+
namespace otel_api
7+
{
8+
class IgnoringVectoringExceptionHandler
9+
{
10+
const PVOID exceptionHandlerHandle{};
11+
static LONG NTAPI exceptionHandler( PEXCEPTION_POINTERS /* exception */ ) noexcept
12+
{
13+
return EXCEPTION_CONTINUE_EXECUTION;
14+
}
15+
16+
public:
17+
IgnoringVectoringExceptionHandler() noexcept
18+
: exceptionHandlerHandle{ AddVectoredExceptionHandler( 1 /* FIRST */, exceptionHandler ) }
19+
{
20+
}
21+
~IgnoringVectoringExceptionHandler() noexcept
22+
{
23+
RemoveVectoredExceptionHandler( exceptionHandlerHandle );
24+
}
25+
};
26+
27+
static bool otel_api_usable_noexhandler()
28+
{
29+
char buf[16]{};
30+
// Gated feature as it's still experimental
31+
GetEnvironmentVariableA( "OTEL_ENABLED", buf, sizeof( buf ) );
32+
const bool OtelEnabled{ ( buf[0] == '1' && buf[1] == 0 ) };
33+
if ( !otelEnabled )
34+
{
35+
return false;
36+
}
37+
38+
// Lookup if the dll has been loaded.
39+
auto mod{ GetModuleHandleW( L"otel_sdk_r" ) };
40+
if ( !mod )
41+
{
42+
mod = GetModuleHandleW( L"otel_sdk_d" );
43+
}
44+
if ( !mod )
45+
{
46+
mod = GetModuleHandleW( L"otel_sdk_rd" );
47+
}
48+
if ( !mod )
49+
{
50+
// No need to report anything here, it's expected that the dll might not be loaded.
51+
return false;
52+
}
53+
// Lookup a function we'll try to call. Similar test is done in otel_sdk::otel_usable
54+
const auto pGetBoolEnvironmentVariable{ reinterpret_cast<bool ( * )( const char *, bool &result )>( GetProcAddress( mod, "?GetBoolEnvironmentVariable@common@sdk@v2@opentelemetry@@YA_NPEBDAEA_N@Z" ) ) };
55+
if ( !pGetBoolEnvironmentVariable )
56+
{
57+
fprintf( stderr, "\nWARNING: [otel_api] Wrong otel_sdk_{r,rd,d}.dll loaded, function lookup failed\n\n" );
58+
return false;
59+
}
60+
DWORD exceptionCode{};
61+
__try
62+
{
63+
bool ignored{};
64+
// Try to call the function. If any exception happens, mark the loaded otel as unusable.
65+
pGetBoolEnvironmentVariable( "", ignored );
66+
return true;
67+
}
68+
__except ( EXCEPTION_EXECUTE_HANDLER )
69+
{
70+
exceptionCode = GetExceptionCode();
71+
}
72+
fprintf( stderr, "\nWARNING: [otel_api] Wrong otel_sdk_{r,rd,d}.dll loaded, error=0x%08.8X\n\n", exceptionCode );
73+
return false;
74+
}
75+
76+
77+
// Check if otel_sdk_{r,d,rd}.dll can be used
78+
// We do a similar verification in otel_sdk_usable()
79+
static bool otel_api_usable()
80+
{
81+
// In case different vectored exception handler is install, ours would take priority
82+
otel_api::IgnoringVectoringExceptionHandler handler;
83+
return otel_api_usable_noexhandler();
84+
}
85+
86+
87+
bool enabled() noexcept
88+
{
89+
static bool usable = otel_api_usable();
90+
// For now, if the API is usable, we treat it as being enabled too.
91+
return usable;
92+
}
93+
} // namespace otel_api

x/hang/otel_api.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
namespace otel_api
4+
{
5+
// Quickly check if otel_sdk_{r,d,rd} has been loaded, and ready to use.
6+
bool enabled() noexcept;
7+
8+
} // namespace otel_api

0 commit comments

Comments
 (0)