Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix trace sdk builder 1393 #1471

Merged
merged 21 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6861368
Draft - work in progress
marcalff Jun 21, 2022
af9a5f2
Merge branch 'open-telemetry:main' into fix_trace_sdk_builder_1393
marcalff Jun 30, 2022
777a4fc
[Trace SDK] Implement builders (#1393)
marcalff Jun 30, 2022
356ef47
[Trace SDK] Implement builders (#1393)
marcalff Jun 30, 2022
250bcde
[Trace SDK] Implement builders (#1393)
marcalff Jun 30, 2022
7041253
[Trace SDK] Implement builders (#1393)
marcalff Jul 1, 2022
a176c4c
[Trace SDK] Implement builders (#1393)
marcalff Jul 1, 2022
c94c174
[Trace SDK] Implement builders (#1393)
marcalff Jul 1, 2022
89fbfbe
Merge branch 'main' into fix_trace_sdk_builder_1393
ThomsonTan Jul 5, 2022
bfc1030
[Trace SDK] Implement builders (#1393)
marcalff Jul 8, 2022
8a4eadc
Merge branch 'main' into fix_trace_sdk_builder_1393
marcalff Jul 9, 2022
f8fe74d
[Trace SDK] Implement builders (#1393)
marcalff Jul 9, 2022
83e7a1c
Merge branch 'open-telemetry:main' into fix_trace_sdk_builder_1393
marcalff Jul 9, 2022
755df64
[Trace SDK] Implement builders (#1393)
marcalff Jul 12, 2022
9cd6bb9
[Trace SDK] Implement builders (#1393)
marcalff Jul 12, 2022
2ad543a
Merge branch 'open-telemetry:main' into fix_trace_sdk_builder_1393
marcalff Jul 12, 2022
9077623
[Trace SDK] Implement builders (#1393)
marcalff Jul 12, 2022
08fb578
Merge branch 'main' into fix_trace_sdk_builder_1393
lalitb Jul 13, 2022
1dea7f3
[Trace SDK] Implement builders (#1393)
marcalff Jul 13, 2022
d4b651e
[Trace SDK] Implement builders (#1393)
marcalff Jul 13, 2022
40217d5
[Trace SDK] Implement builders (#1393)
marcalff Jul 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions docs/cpp-sdk-factory-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# SDK Factory Design

The use cases for applications calling the opentelemetry SDK can be
classified into the following two broad categories:

- SDK users, the application needs to assemble a trace provider / metrics
provider / log provider by assembling available SDK elements,
- SDK implementors, the application needs to extend the opentelemetry SDK
by implementing new features.

## SDK users
marcalff marked this conversation as resolved.
Show resolved Hide resolved

Assume an application 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 rebuild (with a fixed version), redistributed,
marcalff marked this conversation as resolved.
Show resolved Hide resolved
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::Build(opts);
```

While the application code does not change much,
the amount of SDK internals exposed to the application is reduced
significantly.

OtlpGrpcExporterFactory::Build() 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 implementors

Applications that 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).
25 changes: 16 additions & 9 deletions examples/batch/main.cc
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/sdk/trace/tracer_provider.h"
/* API */

#include "opentelemetry/trace/provider.h"

/* SDK */

#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"

/* Exporter */

// Using an exporter that simply dumps span data to stdout.
#include "opentelemetry/exporters/ostream/span_exporter.h"
#include "opentelemetry/sdk/trace/batch_span_processor.h"
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
marcalff marked this conversation as resolved.
Show resolved Hide resolved

#include <chrono>
#include <thread>

constexpr int kNumSpans = 10;
namespace trace_api = opentelemetry::trace;
namespace resource = opentelemetry::sdk::resource;
namespace exporter_trace = opentelemetry::exporter::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace trace_exporter = opentelemetry::exporter::trace;
namespace nostd = opentelemetry::nostd;

namespace
{

void initTracer()
{
auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exporter_trace::OStreamSpanExporter);
auto exporter = trace_exporter::OStreamSpanExporterFactory::Build();

// CONFIGURE BATCH SPAN PROCESSOR PARAMETERS

Expand All @@ -38,11 +46,10 @@ void initTracer()
resource::ResourceAttributes attributes = {{"service", "test_service"}, {"version", (uint32_t)1}};
auto resource = resource::Resource::Create(attributes);

auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
new trace_sdk::BatchSpanProcessor(std::move(exporter), options));
auto processor = trace_sdk::BatchSpanProcessorFactory::Build(std::move(exporter), options);

auto provider = trace_sdk::TracerProviderFactory::Build(std::move(processor), resource);

auto provider = nostd::shared_ptr<trace_api::TracerProvider>(
new trace_sdk::TracerProvider(std::move(processor), resource));
// Set the global trace provider.
trace_api::Provider::SetTracerProvider(provider);
}
Expand Down
27 changes: 17 additions & 10 deletions examples/grpc/tracer_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once
#include "opentelemetry/exporters/ostream/span_exporter.h"
#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/trace/provider.h"

/* API */

#include "opentelemetry/context/propagation/global_propagator.h"
#include "opentelemetry/context/propagation/text_map_propagator.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"
#include "opentelemetry/trace/provider.h"

/* SDK */

#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_context.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"

/* Exporter */

#include "opentelemetry/exporters/ostream/span_exporter_factory.h"

#include <grpcpp/grpcpp.h>
#include <cstring>
Expand Down Expand Up @@ -70,16 +79,14 @@ class GrpcServerCarrier : public opentelemetry::context::propagation::TextMapCar

void initTracer()
{
auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
new opentelemetry::exporter::trace::OStreamSpanExporter);
auto processor = std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
new opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Build();
auto processor =
opentelemetry::sdk::trace::SimpleSpanProcessorFactory::Build(std::move(exporter));
std::vector<std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>> processors;
processors.push_back(std::move(processor));
// Default is an always-on sampler.
auto context = std::make_shared<opentelemetry::sdk::trace::TracerContext>(std::move(processors));
auto provider = opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
new opentelemetry::sdk::trace::TracerProvider(context));
auto provider = opentelemetry::sdk::trace::TracerProviderFactory::Build(context);
// Set the global trace provider
opentelemetry::trace::Provider::SetTracerProvider(provider);

Expand Down
16 changes: 7 additions & 9 deletions examples/http/tracer_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once
#include "opentelemetry/exporters/ostream/span_exporter.h"
#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"

#include "opentelemetry/context/propagation/global_propagator.h"
Expand Down Expand Up @@ -59,16 +59,14 @@ class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCa

void initTracer()
{
auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
new opentelemetry::exporter::trace::OStreamSpanExporter);
auto processor = std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
new opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Build();
auto processor =
opentelemetry::sdk::trace::SimpleSpanProcessorFactory::Build(std::move(exporter));
std::vector<std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>> processors;
processors.push_back(std::move(processor));
// Default is an always-on sampler.
auto context = std::make_shared<opentelemetry::sdk::trace::TracerContext>(std::move(processors));
auto provider = opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
new opentelemetry::sdk::trace::TracerProvider(context));
auto provider = opentelemetry::sdk::trace::TracerProviderFactory::Build(context);
// Set the global trace provider
opentelemetry::trace::Provider::SetTracerProvider(provider);

Expand Down
14 changes: 6 additions & 8 deletions examples/jaeger/main.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/exporters/jaeger/jaeger_exporter.h"
#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/exporters/jaeger/jaeger_exporter_factory.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"

#ifdef BAZEL_BUILD
Expand All @@ -23,11 +23,9 @@ opentelemetry::exporter::jaeger::JaegerExporterOptions opts;
void InitTracer()
{
// Create Jaeger exporter instance
auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new jaeger::JaegerExporter(opts));
auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
auto provider =
nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor)));
auto exporter = jaeger::JaegerExporterFactory::Build(opts);
auto processor = trace_sdk::SimpleSpanProcessorFactory::Build(std::move(exporter));
auto provider = trace_sdk::TracerProviderFactory::Build(std::move(processor));
// Set the global trace provider
trace::Provider::SetTracerProvider(provider);
}
Expand Down
3 changes: 2 additions & 1 deletion examples/multi_processor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include
add_executable(example_multi_processor main.cc)
target_link_libraries(
example_multi_processor ${CMAKE_THREAD_LIBS_INIT} common_foo_library
opentelemetry_trace opentelemetry_exporter_ostream_span)
opentelemetry_trace opentelemetry_exporter_ostream_span
opentelemetry_exporter_memory_trace)
Loading