Description
Describe your environment
We are using the opentelemetry tracing API (and SDK) inside a Linux C++ shared library (.so file) built with the standard gcc toolchain. This library is provides messaging using the AMQP protocol (the library is Qpid Proton C++). We create tracing spans internal to the library to represent the lifecycle of messages sent and received by the library. The contexts associated with the spans are propagated with the messages so that distributed tracing is achieved.
The intention is that any application using our library should be able to create its own tracing spans that are naturally related to the library generated spans (by default using the active span as the parent span). This requires that the TracingProvider accessible to the library and to the application using it is the same TracingProvider.
Steps to reproduce
Our library is built with -fvisibility=hidden
. This means that any symbol that should be exported from the library needs some extra annotation (__attribute__((visibility("default")))
for gcc/clang). We use this to carefully control the visible API/ABI from our library and to be sure that internal details aren't visible outside.
However the way that the singleton insideProvider
is implemented in a header file means that it is defined as a static symbol inside the inline member function Provider::GetProvider
. This means that there are duplicate symbols for every time the provider.h
header file is included in for example our library and an application that uses it.
If the symbols are all visible to the linker at link and runtime then the symbol will be effectively deduplicated and there will be only one used - to my understanding the application symbol takes precedence, but as long as there is only one it will work correctly.
However when the library symbols are hidden by default as in our library there is no way for the runtime loader to know that there should only be one version of the singleton and what happens is that the library and the application end up with different TracerProvider
s.
This is a serious problem for us as we ship our library with the symbols exported explicitly for very good reason and so we can't just use Provider::GetTracerProvider
in the library and application and have it work correctly together.
What is the expected behavior?
The way I would expect this to work is that the singletons are not defined in header files and so duplicated in every object file that includes them, but rather the header file only declares Provider::GetProvider
and it is defined in one of the opentelemetry-cpp libraries (the common lib?). I understand that this moves the singleton out of what you think of as the 'API' and into the 'SDK'. But I really think that architecturally singletons are actuall implementation artifacts not API artifiacts.
Additional context
I note that this is not an issue at all if you statically link everything as in that case the final link phase takes care of the issue.
I also note that this should be an issue using DLLs on windows as by symbols are not exported by default (afair) and also need to be explicitly marked to be exported (using __declspec(dllexport)