Skip to content

Commit e511f6e

Browse files
authored
[OTLP GRPC] Allow user use custom grpc::ChannelArguments (#3990)
1 parent e4aea65 commit e511f6e

4 files changed

Lines changed: 130 additions & 39 deletions

File tree

exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_client.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class Arena;
3535
}
3636
} // namespace google
3737

38+
namespace grpc
39+
{
40+
class ChannelArguments;
41+
} // namespace grpc
42+
3843
namespace opentelemetry
3944
{
4045
namespace proto
@@ -254,6 +259,13 @@ class OtlpGrpcClient
254259
bool IsShutdown() const noexcept;
255260

256261
private:
262+
friend class OtlpGrpcClientTestPeer;
263+
264+
// Populate gRPC channel arguments from exporter options. Shared by MakeChannel() and unit
265+
// tests.
266+
static void PopulateChannelArguments(const OtlpGrpcClientOptions &options,
267+
grpc::ChannelArguments &grpc_arguments);
268+
257269
// Stores if this gRPC client had its Shutdown() method called
258270
std::atomic<bool> is_shutdown_;
259271

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
namespace grpc
1414
{
1515
class ChannelCredentials;
16-
}
16+
class ChannelArguments;
17+
} // namespace grpc
1718

1819
OPENTELEMETRY_BEGIN_NAMESPACE
1920
namespace exporter
@@ -90,6 +91,13 @@ struct OtlpGrpcClientOptions
9091

9192
/** The backoff will be multiplied by this value after each retry attempt. */
9293
float retry_policy_backoff_multiplier{};
94+
95+
/**
96+
* Optional caller-provided gRPC channel arguments.
97+
* This is a non-owning pointer. If set, the pointed-to object must remain valid
98+
* until the gRPC exporter or client has been constructed.
99+
*/
100+
const grpc::ChannelArguments *channel_arguments{};
93101
};
94102

95103
} // namespace otlp

exporters/otlp/src/otlp_grpc_client.cc

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,52 @@ std::shared_ptr<grpc::Channel> OtlpGrpcClient::MakeChannel(const OtlpGrpcClientO
356356
}
357357

358358
grpc::ChannelArguments grpc_arguments;
359+
PopulateChannelArguments(options, grpc_arguments);
360+
361+
if (options.use_ssl_credentials)
362+
{
363+
grpc::SslCredentialsOptions ssl_opts;
364+
ssl_opts.pem_root_certs = GetFileContentsOrInMemoryContents(
365+
options.ssl_credentials_cacert_path, options.ssl_credentials_cacert_as_string);
366+
#ifdef ENABLE_OTLP_GRPC_SSL_MTLS_PREVIEW
367+
ssl_opts.pem_private_key = GetFileContentsOrInMemoryContents(options.ssl_client_key_path,
368+
options.ssl_client_key_string);
369+
ssl_opts.pem_cert_chain = GetFileContentsOrInMemoryContents(options.ssl_client_cert_path,
370+
options.ssl_client_cert_string);
371+
372+
#endif
373+
channel =
374+
grpc::CreateCustomChannel(grpc_target, grpc::SslCredentials(ssl_opts), grpc_arguments);
375+
}
376+
else
377+
{
378+
channel =
379+
grpc::CreateCustomChannel(grpc_target, grpc::InsecureChannelCredentials(), grpc_arguments);
380+
}
381+
382+
#ifdef ENABLE_OTLP_GRPC_CREDENTIAL_PREVIEW
383+
if (options.credentials)
384+
{
385+
if (options.use_ssl_credentials)
386+
{
387+
OTEL_INTERNAL_LOG_WARN(
388+
"[OTLP GRPC Client] Both 'credentials' and 'use_ssl_credentials' options are set. "
389+
"The former takes priority.");
390+
}
391+
channel = grpc::CreateCustomChannel(grpc_target, options.credentials, grpc_arguments);
392+
}
393+
#endif // ENABLE_OTLP_GRPC_CREDENTIAL_PREVIEW
394+
395+
return channel;
396+
}
397+
398+
void OtlpGrpcClient::PopulateChannelArguments(const OtlpGrpcClientOptions &options,
399+
grpc::ChannelArguments &grpc_arguments)
400+
{
401+
if (options.channel_arguments != nullptr)
402+
{
403+
grpc_arguments = *options.channel_arguments;
404+
}
359405
grpc_arguments.SetUserAgentPrefix(options.user_agent);
360406

361407
if (options.max_threads > 0)
@@ -399,9 +445,7 @@ std::shared_ptr<grpc::Channel> OtlpGrpcClient::MakeChannel(const OtlpGrpcClientO
399445
]
400446
})"};
401447

402-
// Allocate string with buffer large enough to hold the formatted json config
403448
auto service_config = std::string(kServiceConfigJson.size(), '\0');
404-
// Prior to C++17, need to explicitly cast away constness from `data()` buffer
405449
std::snprintf(
406450
const_cast<decltype(service_config)::value_type *>(service_config.data()),
407451
service_config.size(), kServiceConfigJson.data(), options.retry_policy_max_attempts,
@@ -412,42 +456,6 @@ std::shared_ptr<grpc::Channel> OtlpGrpcClient::MakeChannel(const OtlpGrpcClientO
412456
grpc_arguments.SetServiceConfigJSON(service_config);
413457
}
414458
#endif // ENABLE_OTLP_RETRY_PREVIEW
415-
416-
if (options.use_ssl_credentials)
417-
{
418-
grpc::SslCredentialsOptions ssl_opts;
419-
ssl_opts.pem_root_certs = GetFileContentsOrInMemoryContents(
420-
options.ssl_credentials_cacert_path, options.ssl_credentials_cacert_as_string);
421-
#ifdef ENABLE_OTLP_GRPC_SSL_MTLS_PREVIEW
422-
ssl_opts.pem_private_key = GetFileContentsOrInMemoryContents(options.ssl_client_key_path,
423-
options.ssl_client_key_string);
424-
ssl_opts.pem_cert_chain = GetFileContentsOrInMemoryContents(options.ssl_client_cert_path,
425-
options.ssl_client_cert_string);
426-
427-
#endif
428-
channel =
429-
grpc::CreateCustomChannel(grpc_target, grpc::SslCredentials(ssl_opts), grpc_arguments);
430-
}
431-
else
432-
{
433-
channel =
434-
grpc::CreateCustomChannel(grpc_target, grpc::InsecureChannelCredentials(), grpc_arguments);
435-
}
436-
437-
#ifdef ENABLE_OTLP_GRPC_CREDENTIAL_PREVIEW
438-
if (options.credentials)
439-
{
440-
if (options.use_ssl_credentials)
441-
{
442-
OTEL_INTERNAL_LOG_WARN(
443-
"[OTLP GRPC Client] Both 'credentials' and 'use_ssl_credentials' options are set. "
444-
"The former takes priority.");
445-
}
446-
channel = grpc::CreateCustomChannel(grpc_target, options.credentials, grpc_arguments);
447-
}
448-
#endif // ENABLE_OTLP_GRPC_CREDENTIAL_PREVIEW
449-
450-
return channel;
451459
}
452460

453461
std::unique_ptr<grpc::ClientContext> OtlpGrpcClient::MakeClientContext(

exporters/otlp/test/otlp_grpc_target_test.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
#include <grpc/grpc.h>
5+
#include <grpcpp/support/channel_arguments.h>
46
#include <gtest/gtest.h>
7+
8+
#include <cstring>
59
#include <string>
610

711
#include "opentelemetry/exporters/otlp/otlp_grpc_client.h"
@@ -14,6 +18,36 @@ namespace exporter
1418
namespace otlp
1519
{
1620

21+
namespace
22+
{
23+
24+
const grpc_arg *FindChannelArg(const grpc_channel_args &channel_args, const char *key)
25+
{
26+
for (std::size_t i = 0; i < channel_args.num_args; ++i)
27+
{
28+
const grpc_arg &arg = channel_args.args[i];
29+
if (arg.key != nullptr && std::strcmp(arg.key, key) == 0)
30+
{
31+
return &arg;
32+
}
33+
}
34+
35+
return nullptr;
36+
}
37+
38+
} // namespace
39+
40+
class OtlpGrpcClientTestPeer : public ::testing::Test
41+
{
42+
public:
43+
static grpc::ChannelArguments BuildChannelArguments(const OtlpGrpcClientOptions &options)
44+
{
45+
grpc::ChannelArguments grpc_arguments;
46+
OtlpGrpcClient::PopulateChannelArguments(options, grpc_arguments);
47+
return grpc_arguments;
48+
}
49+
};
50+
1751
TEST(OtlpGrpcClientEndpointTest, GrpcClientTest)
1852
{
1953
OtlpGrpcClientOptions opts1;
@@ -34,6 +68,35 @@ TEST(OtlpGrpcClientEndpointTest, GrpcClientTest)
3468
EXPECT_EQ(target3, "localhost:4317");
3569
}
3670

71+
TEST_F(OtlpGrpcClientTestPeer, ChannelArgumentsOptionTest)
72+
{
73+
OtlpGrpcClientOptions options;
74+
options.user_agent = "otlp-grpc-target-test";
75+
76+
grpc::ChannelArguments channel_arguments;
77+
channel_arguments.SetMaxReceiveMessageSize(1);
78+
options.channel_arguments = &channel_arguments;
79+
80+
auto built_arguments = BuildChannelArguments(options);
81+
channel_arguments.SetMaxReceiveMessageSize(-1);
82+
83+
auto built_channel_args = built_arguments.c_channel_args();
84+
85+
const grpc_arg *max_receive_arg =
86+
FindChannelArg(built_channel_args, GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH);
87+
ASSERT_NE(max_receive_arg, nullptr);
88+
EXPECT_EQ(max_receive_arg->type, GRPC_ARG_INTEGER);
89+
EXPECT_EQ(max_receive_arg->value.integer, 1);
90+
91+
const grpc_arg *user_agent_arg =
92+
FindChannelArg(built_channel_args, GRPC_ARG_PRIMARY_USER_AGENT_STRING);
93+
ASSERT_NE(user_agent_arg, nullptr);
94+
EXPECT_EQ(user_agent_arg->type, GRPC_ARG_STRING);
95+
EXPECT_EQ(std::strncmp(user_agent_arg->value.string, options.user_agent.c_str(),
96+
options.user_agent.size()),
97+
0);
98+
}
99+
37100
} // namespace otlp
38101
} // namespace exporter
39102
OPENTELEMETRY_END_NAMESPACE

0 commit comments

Comments
 (0)