Skip to content

Commit

Permalink
[EXPORTER] Support handling retry-able errors for OTLP/gRPC (#3219)
Browse files Browse the repository at this point in the history
  • Loading branch information
chusitoo authored Jan 21, 2025
1 parent d2ff95a commit 031307b
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Increment the:
* [EXPORTER] Support handling retry-able errors for OTLP/HTTP
[#3223](https://github.com/open-telemetry/opentelemetry-cpp/pull/3223)

* [EXPORTER] Support handling retry-able errors for OTLP/gRPC
[#3219](https://github.com/open-telemetry/opentelemetry-cpp/pull/3219)

New features:

* [SDK] Better control of threads executed by opentelemetry-cpp
Expand Down
1 change: 1 addition & 0 deletions ci/do_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ elif [[ "$1" == "cmake.exporter.otprotocol.test" ]]; then
-DWITH_OTLP_HTTP=ON \
-DWITH_OTLP_FILE=ON \
-DWITH_OTLP_GRPC_SSL_MTLS_PREVIEW=ON \
-DWITH_OTLP_RETRY_PREVIEW=ON \
"${SRC_DIR}"
grpc_cpp_plugin=`which grpc_cpp_plugin`
proto_make_file="CMakeFiles/opentelemetry_proto.dir/build.make"
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ if(BUILD_TESTING)
add_executable(otlp_grpc_exporter_test test/otlp_grpc_exporter_test.cc)
target_link_libraries(
otlp_grpc_exporter_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
${GMOCK_LIB} opentelemetry_exporter_otlp_grpc)
${GMOCK_LIB} opentelemetry_exporter_otlp_grpc gRPC::grpc++)
gtest_add_tests(
TARGET otlp_grpc_exporter_test
TEST_PREFIX exporter.otlp.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ struct OtlpGrpcClientOptions
// Concurrent requests
std::size_t max_concurrent_requests;
#endif

/** The maximum number of call attempts, including the original attempt. */
std::uint32_t retry_policy_max_attempts{};

/** The initial backoff delay between retry attempts, random between (0, initial_backoff). */
std::chrono::duration<float> retry_policy_initial_backoff{};

/** The maximum backoff places an upper limit on exponential backoff growth. */
std::chrono::duration<float> retry_policy_max_backoff{};

/** The backoff will be multiplied by this value after each retry attempt. */
float retry_policy_backoff_multiplier{};
};

} // namespace otlp
Expand Down
45 changes: 45 additions & 0 deletions exporters/otlp/src/otlp_grpc_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdio>
#include <fstream>
#include <iterator>
#include <memory>
Expand All @@ -23,6 +24,7 @@
#include "opentelemetry/common/timestamp.h"
#include "opentelemetry/ext/http/common/url_parser.h"
#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/sdk/common/global_log_handler.h"

OPENTELEMETRY_BEGIN_NAMESPACE
Expand Down Expand Up @@ -347,6 +349,49 @@ std::shared_ptr<grpc::Channel> OtlpGrpcClient::MakeChannel(const OtlpGrpcClientO
grpc_arguments.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP);
}

#ifdef ENABLE_OTLP_RETRY_PREVIEW
if (options.retry_policy_max_attempts > 0U &&
options.retry_policy_initial_backoff > std::chrono::duration<float>::zero() &&
options.retry_policy_max_backoff > std::chrono::duration<float>::zero() &&
options.retry_policy_backoff_multiplier > 0.0f)
{
static const auto kServiceConfigJson = opentelemetry::nostd::string_view{R"(
{
"methodConfig": [
{
"name": [{}],
"retryPolicy": {
"maxAttempts": %0000000000u,
"initialBackoff": "%0000000000.1fs",
"maxBackoff": "%0000000000.1fs",
"backoffMultiplier": %0000000000.1f,
"retryableStatusCodes": [
"CANCELLED",
"DEADLINE_EXCEEDED",
"ABORTED",
"OUT_OF_RANGE",
"DATA_LOSS",
"UNAVAILABLE"
]
}
}
]
})"};

// Allocate string with buffer large enough to hold the formatted json config
auto service_config = std::string(kServiceConfigJson.size(), '\0');
// Prior to C++17, need to explicitly cast away constness from `data()` buffer
std::snprintf(
const_cast<decltype(service_config)::value_type *>(service_config.data()),
service_config.size(), kServiceConfigJson.data(), options.retry_policy_max_attempts,
std::min(std::max(options.retry_policy_initial_backoff.count(), 0.f), 999999999.f),
std::min(std::max(options.retry_policy_max_backoff.count(), 0.f), 999999999.f),
std::min(std::max(options.retry_policy_backoff_multiplier, 0.f), 999999999.f));

grpc_arguments.SetServiceConfigJSON(service_config);
}
#endif // ENABLE_OTLP_RETRY_PREVIEW

if (options.use_ssl_credentials)
{
grpc::SslCredentialsOptions ssl_opts;
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/src/otlp_grpc_exporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ sdk::common::ExportResult OtlpGrpcExporter::Export(
google::protobuf::ArenaOptions arena_options;
// It's easy to allocate datas larger than 1024 when we populate basic resource and attributes
arena_options.initial_block_size = 1024;
// When in batch mode, it's easy to export a large number of spans at once, we can alloc a lager
// When in batch mode, it's easy to export a large number of spans at once, we can alloc a larger
// block to reduce memory fragments.
arena_options.max_block_size = 65536;
std::unique_ptr<google::protobuf::Arena> arena{new google::protobuf::Arena{arena_options}};
Expand Down
5 changes: 5 additions & 0 deletions exporters/otlp/src/otlp_grpc_exporter_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ OtlpGrpcExporterOptions::OtlpGrpcExporterOptions()
#ifdef ENABLE_ASYNC_EXPORT
max_concurrent_requests = 64;
#endif

retry_policy_max_attempts = GetOtlpDefaultTracesRetryMaxAttempts();
retry_policy_initial_backoff = GetOtlpDefaultTracesRetryInitialBackoff();
retry_policy_max_backoff = GetOtlpDefaultTracesRetryMaxBackoff();
retry_policy_backoff_multiplier = GetOtlpDefaultTracesRetryBackoffMultiplier();
}

OtlpGrpcExporterOptions::~OtlpGrpcExporterOptions() {}
Expand Down
5 changes: 5 additions & 0 deletions exporters/otlp/src/otlp_grpc_log_record_exporter_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ OtlpGrpcLogRecordExporterOptions::OtlpGrpcLogRecordExporterOptions()
#ifdef ENABLE_ASYNC_EXPORT
max_concurrent_requests = 64;
#endif

retry_policy_max_attempts = GetOtlpDefaultLogsRetryMaxAttempts();
retry_policy_initial_backoff = GetOtlpDefaultLogsRetryInitialBackoff();
retry_policy_max_backoff = GetOtlpDefaultLogsRetryMaxBackoff();
retry_policy_backoff_multiplier = GetOtlpDefaultLogsRetryBackoffMultiplier();
}

OtlpGrpcLogRecordExporterOptions::~OtlpGrpcLogRecordExporterOptions() {}
Expand Down
5 changes: 5 additions & 0 deletions exporters/otlp/src/otlp_grpc_metric_exporter_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ OtlpGrpcMetricExporterOptions::OtlpGrpcMetricExporterOptions()
#ifdef ENABLE_ASYNC_EXPORT
max_concurrent_requests = 64;
#endif

retry_policy_max_attempts = GetOtlpDefaultMetricsRetryMaxAttempts();
retry_policy_initial_backoff = GetOtlpDefaultMetricsRetryInitialBackoff();
retry_policy_max_backoff = GetOtlpDefaultMetricsRetryMaxBackoff();
retry_policy_backoff_multiplier = GetOtlpDefaultMetricsRetryBackoffMultiplier();
}

OtlpGrpcMetricExporterOptions::~OtlpGrpcMetricExporterOptions() {}
Expand Down
Loading

0 comments on commit 031307b

Please sign in to comment.