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

[EXPORTER] Allow to share gRPC clients between OTLP exporters #3041

Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
213e3cf
Allow to share gRPC clients between OTLP exporters.
owent Aug 29, 2024
5c5f9b7
Add changelog, fix compiling problems without async
owent Aug 29, 2024
37e5081
gRPC depends abseil-cp, so we always enable abseil-cpp when have `WIT…
owent Aug 29, 2024
c9cb2df
Fix linking error
owent Aug 29, 2024
0d409d4
Share `grpc::Channel`
owent Aug 30, 2024
cd80d19
Fix compiling error
owent Aug 30, 2024
ad722f4
Make `OtlpGrpcClientReferenceGuard` always available
owent Aug 30, 2024
f4521f3
Try to cancel running requests when shutdown timeout
owent Aug 30, 2024
38860d3
Modify `running_calls` do not depends the thread for gRPC callback.
owent Aug 30, 2024
b5daf3f
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Sep 6, 2024
8e9d300
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Sep 9, 2024
51e0964
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Sep 12, 2024
40ca747
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Sep 18, 2024
b2aa191
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Sep 23, 2024
3547800
Allow to share gRPC Client in sync mode
owent Sep 25, 2024
ef62bc0
Fix shutdown in sync mode
owent Sep 25, 2024
caa1743
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Oct 1, 2024
949c679
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Oct 7, 2024
e1e6627
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 8, 2024
74ceb64
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
lalitb Oct 8, 2024
d5bb715
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 9, 2024
c9419bf
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 14, 2024
d4b0286
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 16, 2024
72e4cb3
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 18, 2024
edd0c16
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 22, 2024
3ff6e4b
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 24, 2024
829294e
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Oct 24, 2024
94260b3
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
ThomsonTan Oct 29, 2024
4367e62
Change unique_ptr and shared_ptr from `nostd::` to `std::`. Change th…
owent Oct 30, 2024
e2b23aa
Fix includes
owent Oct 30, 2024
5142036
Do not inline otabsl to avoid namespace conflicts
owent Oct 30, 2024
d7266aa
Fix markdown lint
owent Oct 30, 2024
603e2fa
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Nov 1, 2024
adcf88e
Merge remote-tracking branch 'github/main' into allow_construct_grpc_…
owent Nov 5, 2024
b71c655
Add internal logs when shutdown gRPC Client
owent Nov 6, 2024
1145003
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
owent Nov 8, 2024
4d4d3a5
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Nov 13, 2024
fe30625
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Nov 13, 2024
7b2f29e
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
marcalff Nov 14, 2024
62756bd
Merge branch 'main' into allow_construct_grpc_exporters_with_existed_…
ThomsonTan Nov 18, 2024
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Increment the:

## [Unreleased]

* [EXPORTER] Allow to share gRPC clients between OTLP exporters.
ThomsonTan marked this conversation as resolved.
Show resolved Hide resolved
[#3041](https://github.com/open-telemetry/opentelemetry-cpp/pull/3041)

* [API] Jaeger Propagator should not be deprecated
[#3086](https://github.com/open-telemetry/opentelemetry-cpp/pull/3086)

Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ if(WITH_PROMETHEUS)
endif()
endif()

if(WITH_ABSEIL)
if(WITH_ABSEIL OR WITH_OTLP_GRPC)
if(NOT TARGET absl::strings)
find_package(absl CONFIG REQUIRED)
endif()
Expand All @@ -380,7 +380,7 @@ if(WITH_OTLP_GRPC
OR WITH_OTLP_FILE)
find_package(Protobuf)
if(Protobuf_VERSION AND Protobuf_VERSION VERSION_GREATER_EQUAL "3.22.0")
if(NOT WITH_ABSEIL)
if(NOT WITH_ABSEIL AND NOT WITH_OTLP_GRPC)
message(
FATAL_ERROR
"Protobuf 3.22 or upper require abseil-cpp(Recommended version: 20230125 or upper)"
Expand Down
2 changes: 1 addition & 1 deletion api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if(WITH_NO_DEPRECATED_CODE)
INTERFACE OPENTELEMETRY_NO_DEPRECATED_CODE)
endif()

if(WITH_ABSEIL)
if(WITH_ABSEIL OR WITH_OTLP_GRPC)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@owent It might be better not to enforce HAVE_ABSEIL at this point. Perhaps we can address it in a separate PR, allowing this one to focus solely on sharing the gRPC client. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a crash before, in which case some codes are compiled without HAVE_ABSEIL, but the codes in gRPC exporters must be compiled with it. I think it's the simplest way to keep compatibility to enforce abseil-cpp when using gRPC exporters now.
I think we can remove it if we change the include paths of all bundled version of abseil-cpp, or there will be conflicts.( Some codes in gRPC exporters will be compiled with the bundled version of abseil-cpp because of the search order of headers, and the gRPC library is built with the external version)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the crash related to code within this PR. As there is no crash observed before that ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR will use the new headers which also includes abseil-cpp's headers in some versions of gRPC.Without this macro, gRPC's headers may include the bundled version of abseil-cpp in otel-cpp.
The codes before did not use these new headers but there are still problems when otel-cpp's api use headers from the bundled version, but gRPC exporters use the external version. I think it's UB, and may lead to export nothing when using gRPC exporter.

In my understanding, the best solution is to change the file paths of bundled version of abseil, so the two versions will not share the same include path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this only apply to protobuf 3.21 and below? With protobuf 3.22, the SDK build will fail if WITH_OTLP_GRPC is enabled without WITH_ABSEIL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to protobuf, gRpc always depends abseil-cpp. gRPC depends external abseil-cpp.
Maybe we can let all gRPC exporters always search headers from third party's include paths first so they will not use headers from bundled version.

Copy link
Member Author

@owent owent Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/open-telemetry/opentelemetry-cpp/actions/runs/11596474550/job/32287629537?pr=3041
The conflicts are show here, can I remove inline namespace for bundled absl to avoid conflicts? The ABI will not change and the abseil requirement for protobuf can also be removed when namespace conflict is resolved.
@lalitb @ThomsonTan

target_compile_definitions(opentelemetry_api INTERFACE HAVE_ABSEIL)
target_link_libraries(
opentelemetry_api INTERFACE absl::bad_variant_access absl::any absl::base
Expand Down
18 changes: 7 additions & 11 deletions cmake/opentelemetry-proto.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,10 @@ add_library(
set_target_version(opentelemetry_proto)

# Disable include-what-you-use on generated code.
set_target_properties(
opentelemetry_proto
PROPERTIES CXX_INCLUDE_WHAT_YOU_USE ""
)
set_target_properties(opentelemetry_proto PROPERTIES CXX_INCLUDE_WHAT_YOU_USE
ThomsonTan marked this conversation as resolved.
Show resolved Hide resolved
"")

if(WITH_ABSEIL)
if(WITH_ABSEIL OR WITH_OTLP_GRPC)
target_link_libraries(opentelemetry_proto PUBLIC absl::bad_variant_access)
endif()

Expand Down Expand Up @@ -393,12 +391,10 @@ else() # cmake 3.8 or lower
endif()

if(WITH_OTLP_GRPC)
if(WITH_ABSEIL)
find_package(absl CONFIG)
if(TARGET absl::synchronization)
target_link_libraries(opentelemetry_proto_grpc
PRIVATE absl::synchronization)
endif()
find_package(absl CONFIG)
if(TARGET absl::synchronization)
target_link_libraries(opentelemetry_proto_grpc
PRIVATE absl::synchronization)
endif()
endif()

Expand Down
2 changes: 1 addition & 1 deletion cmake/patch-imported-config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if(TARGET CURL::libcurl
endif()

# abseil targets
if(WITH_ABSEIL)
if(WITH_ABSEIL OR WITH_OTLP_GRPC)
project_build_tools_patch_default_imported_config(
absl::bad_variant_access
absl::raw_logging_internal
Expand Down
2 changes: 1 addition & 1 deletion examples/grpc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ else()
target_link_libraries(example_grpc_proto PUBLIC gRPC::grpc++
${Protobuf_LIBRARIES})
endif()
if(WITH_ABSEIL)
if(WITH_ABSEIL OR WITH_OTLP_GRPC)
target_link_libraries(example_grpc_proto PUBLIC absl::bad_variant_access)
endif()

Expand Down
2 changes: 2 additions & 0 deletions exporters/otlp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ cc_library(
name = "otlp_grpc_client",
srcs = [
"src/otlp_grpc_client.cc",
"src/otlp_grpc_client_factory.cc",
"src/otlp_grpc_utils.cc",
],
hdrs = [
"include/opentelemetry/exporters/otlp/otlp_environment.h",
"include/opentelemetry/exporters/otlp/otlp_grpc_client.h",
"include/opentelemetry/exporters/otlp/otlp_grpc_client_factory.h",
"include/opentelemetry/exporters/otlp/otlp_grpc_client_options.h",
"include/opentelemetry/exporters/otlp/otlp_grpc_utils.h",
"include/opentelemetry/exporters/otlp/protobuf_include_prefix.h",
Expand Down
6 changes: 4 additions & 2 deletions exporters/otlp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ target_link_libraries(opentelemetry_otlp_recordable

if(WITH_OTLP_GRPC)
find_package(gRPC REQUIRED)
add_library(opentelemetry_exporter_otlp_grpc_client src/otlp_grpc_client.cc
src/otlp_grpc_utils.cc)
add_library(
opentelemetry_exporter_otlp_grpc_client
src/otlp_grpc_client.cc src/otlp_grpc_client_factory.cc
src/otlp_grpc_utils.cc)
set_target_properties(opentelemetry_exporter_otlp_grpc_client
PROPERTIES EXPORT_NAME otlp_grpc_client)
set_target_version(opentelemetry_exporter_otlp_grpc_client)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,52 @@

#include "opentelemetry/exporters/otlp/otlp_grpc_client_options.h"

// clang-format off
ThomsonTan marked this conversation as resolved.
Show resolved Hide resolved
#include "opentelemetry/exporters/otlp/protobuf_include_prefix.h"
// clang-format on

#include "google/protobuf/arena.h"
#include "opentelemetry/proto/collector/logs/v1/logs_service.grpc.pb.h"
#include "opentelemetry/proto/collector/metrics/v1/metrics_service.grpc.pb.h"
#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h"

// clang-format off
#include "opentelemetry/exporters/otlp/protobuf_include_suffix.h"
// clang-format on

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace otlp
{

class OtlpGrpcClient;
struct OtlpGrpcClientOptions;

#ifdef ENABLE_ASYNC_EXPORT
struct OtlpGrpcClientAsyncData;
#endif

class OtlpGrpcClientReferenceGuard
{
public:
OtlpGrpcClientReferenceGuard() noexcept;
~OtlpGrpcClientReferenceGuard() noexcept;

OtlpGrpcClientReferenceGuard(const OtlpGrpcClientReferenceGuard &) = delete;
OtlpGrpcClientReferenceGuard(OtlpGrpcClientReferenceGuard &&) = delete;
OtlpGrpcClientReferenceGuard &operator=(const OtlpGrpcClientReferenceGuard &) = delete;
OtlpGrpcClientReferenceGuard &operator=(OtlpGrpcClientReferenceGuard &&) = delete;

private:
friend class OtlpGrpcClient;
std::atomic<bool> has_value_;
};

/**
* The OTLP gRPC client contains utility functions of gRPC.
*/
class OtlpGrpcClient
{
public:
OtlpGrpcClient();
OtlpGrpcClient(const OtlpGrpcClientOptions &options);

~OtlpGrpcClient();

Expand All @@ -58,20 +76,18 @@ class OtlpGrpcClient
/**
* Create trace service stub to communicate with the OpenTelemetry Collector.
*/
static std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface>
MakeTraceServiceStub(const OtlpGrpcClientOptions &options);
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> MakeTraceServiceStub();

/**
* Create metrics service stub to communicate with the OpenTelemetry Collector.
*/
static std::unique_ptr<proto::collector::metrics::v1::MetricsService::StubInterface>
MakeMetricsServiceStub(const OtlpGrpcClientOptions &options);
std::unique_ptr<proto::collector::metrics::v1::MetricsService::StubInterface>
MakeMetricsServiceStub();

/**
* Create logs service stub to communicate with the OpenTelemetry Collector.
*/
static std::unique_ptr<proto::collector::logs::v1::LogsService::StubInterface>
MakeLogsServiceStub(const OtlpGrpcClientOptions &options);
std::unique_ptr<proto::collector::logs::v1::LogsService::StubInterface> MakeLogsServiceStub();

static grpc::Status DelegateExport(
proto::collector::trace::v1::TraceService::StubInterface *stub,
Expand All @@ -94,8 +110,18 @@ class OtlpGrpcClient
proto::collector::logs::v1::ExportLogsServiceRequest &&request,
proto::collector::logs::v1::ExportLogsServiceResponse *response);

#ifdef ENABLE_ASYNC_EXPORT
void AddReference(OtlpGrpcClientReferenceGuard &guard,
const OtlpGrpcClientOptions &options) noexcept;

/**
* Reomve reference fro a guard object
*
* @param guard guard object to remove reference from
* @return true if there is no more reference to this gRPC client
*/
bool RemoveReference(OtlpGrpcClientReferenceGuard &guard) noexcept;

#ifdef ENABLE_ASYNC_EXPORT
/**
* Async export
* @param options Options used to message to create gRPC context and stub(if necessary)
Expand Down Expand Up @@ -155,6 +181,7 @@ class OtlpGrpcClient
const proto::collector::logs::v1::ExportLogsServiceRequest &,
proto::collector::logs::v1::ExportLogsServiceResponse *)>
&&result_callback) noexcept;
#endif

/**
* Force flush the gRPC client.
Expand All @@ -167,17 +194,19 @@ class OtlpGrpcClient
* timeout is applied.
* @return return the status of this operation
*/
bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept;
bool Shutdown(OtlpGrpcClientReferenceGuard &guard,
std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept;

std::shared_ptr<OtlpGrpcClientAsyncData> MutableAsyncData(const OtlpGrpcClientOptions &options);

bool IsShutdown() const noexcept;

private:
// Stores if this gRPC client had its Shutdown() method called
std::atomic<bool> is_shutdown_;

// Stores shared data between threads of this gRPC client
std::shared_ptr<OtlpGrpcClientAsyncData> async_data_;
#endif
};
} // namespace otlp
} // namespace exporter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <memory>

#include "opentelemetry/exporters/otlp/otlp_grpc_client_options.h"
#include "opentelemetry/nostd/shared_ptr.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace otlp
{

class OtlpGrpcClientReferenceGuard;
class OtlpGrpcClient;

/**
* Factory class for OtlpGrpcClient.
*/
class OPENTELEMETRY_EXPORT OtlpGrpcClientFactory
{
public:
/**
* Create an OtlpGrpcClient using all default options.
*/
static nostd::shared_ptr<OtlpGrpcClient> Create(const OtlpGrpcClientOptions &options);

static nostd::shared_ptr<OtlpGrpcClientReferenceGuard> CreateReferenceGuard();
};

} // namespace otlp
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
#include <atomic>
#include <chrono>

// clang-format off
#include "opentelemetry/exporters/otlp/protobuf_include_prefix.h"
// clang-format on

#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h"

// clang-format off
#include "opentelemetry/exporters/otlp/protobuf_include_suffix.h"
// clang-format on

#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/sdk/trace/exporter.h"

#include "opentelemetry/exporters/otlp/otlp_environment.h"
Expand All @@ -23,6 +28,8 @@ namespace exporter
namespace otlp
{

class OtlpGrpcClientReferenceGuard;

class OtlpGrpcClient;

/**
Expand All @@ -36,11 +43,22 @@ class OtlpGrpcExporter final : public opentelemetry::sdk::trace::SpanExporter
*/
OtlpGrpcExporter();

/**
* Create an OtlpGrpcExporter using specified OtlpGrpcClient.
*
* @param options options to create exporter
* @param client the gRPC client to use
*/
OtlpGrpcExporter(const OtlpGrpcExporterOptions &options,
nostd::shared_ptr<OtlpGrpcClient> client);
owent marked this conversation as resolved.
Show resolved Hide resolved

/**
* Create an OtlpGrpcExporter using the given options.
*/
explicit OtlpGrpcExporter(const OtlpGrpcExporterOptions &options);

~OtlpGrpcExporter() override;

/**
* Create a span recordable.
* @return a newly initialized Recordable object
Expand Down Expand Up @@ -71,27 +89,43 @@ class OtlpGrpcExporter final : public opentelemetry::sdk::trace::SpanExporter
bool Shutdown(
std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override;

/**
* Get the Client object
*
* @return return binded gRPC client
*/
const nostd::shared_ptr<OtlpGrpcClient> &GetClient() const noexcept;

private:
// The configuration options associated with this exporter.
const OtlpGrpcExporterOptions options_;

#ifdef ENABLE_ASYNC_EXPORT
std::shared_ptr<OtlpGrpcClient> client_;
#endif
nostd::shared_ptr<OtlpGrpcClient> client_;
owent marked this conversation as resolved.
Show resolved Hide resolved
nostd::shared_ptr<OtlpGrpcClientReferenceGuard> client_reference_guard_;

// For testing
friend class OtlpGrpcExporterTestPeer;
friend class OtlpGrpcLogRecordExporterTestPeer;

// Store service stub internally. Useful for testing.
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> trace_service_stub_;
nostd::shared_ptr<proto::collector::trace::v1::TraceService::StubInterface> trace_service_stub_;

/**
* Create an OtlpGrpcExporter using the specified service stub.
* Only tests can call this constructor directly.
* @param stub the service stub to be used for exporting
*/
OtlpGrpcExporter(std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> stub);

/**
* Create an OtlpGrpcExporter using the specified service stub and gRPC client.
* Only tests can call this constructor directly.
* @param stub the service stub to be used for exporting
* @param client the gRPC client to use
*/
OtlpGrpcExporter(std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> stub,
nostd::shared_ptr<OtlpGrpcClient> client);

std::atomic<bool> is_shutdown_{false};
bool isShutdown() const noexcept;
};
Expand Down
Loading
Loading