-
Notifications
You must be signed in to change notification settings - Fork 423
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
68 changed files
with
1,757 additions
and
264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
# SDK Factory Design | ||
|
||
When an application owner needs to configure the opentelemetry SDK, | ||
this can be done in different ways: | ||
|
||
- by assembly of available SDK elements already provided, | ||
- by extension of the SDK to support more functionality. | ||
|
||
The sections below investigate each use case, | ||
and the consequences when using shared libraries. | ||
|
||
Last, a section discuss the impact of C++ conditional parameters | ||
on the SDK interface, and how this affects shared libraries. | ||
|
||
## SDK assembly | ||
|
||
Assume the application owner needs to build a trace provider, using the gRPC trace | ||
exporter. | ||
|
||
### Case study, direct call to the SDK implementation classes | ||
|
||
A possible way to build the exporter is to call, from the application code: | ||
|
||
```cpp | ||
opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; | ||
|
||
auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>( | ||
new opentelemetry::exporter::otlp::OtlpGrpcExporter(opts)); | ||
``` | ||
|
||
When the application code is built and linked against static | ||
opentelemetry-cpp libraries, the result is a binary that is consistent, and | ||
works. | ||
|
||
However, in case of a bug fixed in opentelemetry-cpp itself, the entire | ||
application must be rebuilt (with a fixed version), redistributed, | ||
and reinstalled, to have the bug effectively fixed. | ||
|
||
This is highly undesirable. | ||
|
||
Instead of static libraries, now consider the same application built and | ||
linked against shared (dynamic) libraries instead. | ||
|
||
The desired goal with shared libraries is to allow to: | ||
|
||
- fix a bug in opentelemetry-cpp | ||
- deploy a fixed shared library | ||
- keep the application unchanged. | ||
|
||
For this to be possible, the ABI exposed by the SDK shared library | ||
must be stable. | ||
|
||
Here, class OtlpGrpcExporter is the implementation itself, | ||
and is very likely to change, even for a bug fix, | ||
so it is not a good thing to expose it. | ||
|
||
Setting the constraint on the SDK implementation that class | ||
OtlpGrpcExporter will never change is unrealistic, | ||
because a bug fix might require new members (for example, to add a mutex to | ||
fix a race), which will change the ABI (the memory layout is different), | ||
breaking the application code compiled with a different version. | ||
|
||
In summary, this line of code alone, in the application space: | ||
|
||
new opentelemetry::exporter::otlp::OtlpGrpcExporter(opts); | ||
|
||
prevents in practice any deployment using shared libraries. | ||
|
||
### Case study, using Factory and builders from the SDK | ||
|
||
The SDK also provide Factory classes, that can be used as follows | ||
from the application code: | ||
|
||
```cpp | ||
opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; | ||
|
||
auto exporter = | ||
opentelemetry::exporter::otlp::OtlpGrpcExporterFactory::Create(opts); | ||
``` | ||
While the application code does not change much, | ||
the amount of SDK internals exposed to the application is reduced | ||
significantly. | ||
OtlpGrpcExporterFactory::Create() actually returns a abstract SpanExporter | ||
object, instead of a concrete OtlpGrpcExporter object. | ||
As a result, the application binary is not even aware of the implementation | ||
class OtlpGrpcExporter. | ||
This property makes it possible to: | ||
- implement changes in the SDK itself | ||
- deploy a new SDK shared library | ||
- keep the application unchanged | ||
## SDK extension | ||
Applications owners who want to extend existing SDK classes are expected | ||
to have a stronger dependency on the SDK internals. | ||
For example, with | ||
```cpp | ||
class MyFancyOtlpGrpcExporter : public OtlpGrpcExporter {...} | ||
``` | ||
|
||
the build depends on the actual SDK implementation. | ||
|
||
Class OtlpGrpcExporter is visible in the SDK public header files, | ||
to allow this pattern. | ||
|
||
Using shared libraries in this case is not recommended, | ||
because the SDK implementation is at greater risk of change. | ||
|
||
## Conditional parameters | ||
|
||
Assume Foo() is part of the SDK, delivered as a shared library. | ||
|
||
When an API contains conditional parameters, as in: | ||
|
||
```cpp | ||
void Foo(int x = 0, int y = 0); | ||
``` | ||
this in reality produces 3 APIs usable by the application code: | ||
```cpp | ||
void Foo(); | ||
void Foo(int x); | ||
void Foo(int x, int y); | ||
``` | ||
|
||
as well as 1 ABI provided in a library: | ||
|
||
```cpp | ||
void Foo(int x, int y); | ||
``` | ||
The value of the defaults parameters (x = 0) is compiled in the application | ||
code. | ||
Assume that, for a bug fix, the API definition is changed to: | ||
```cpp | ||
void Foo(int x = 0, int y = 1); | ||
``` | ||
|
||
Deploying a new version of the SDK will have no effect, | ||
because the default value is in the application binary, not the shared | ||
library. | ||
|
||
Now, assume a later change needs to add a new parameter: | ||
|
||
```cpp | ||
void Foo(int x = 0, int y = 1, int z = 2); | ||
``` | ||
Here, clients will call the old Foo(int x, int y) ABI, crashing in the SDK | ||
because the SDK expects 3 parameters, not 2. | ||
Because of this, conditional parameters are to be avoided, | ||
not to be used in the SDK interface. | ||
Note that using conditional parameters in the opentelemetry-cpp API is ok, | ||
because the API is header only (there is no ABI). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.