diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e93602019..788982121d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: ./ci/do_ci.sh cmake.abseil.test cmake_gcc_48_test: - name: CMake gcc 4.8 + name: CMake gcc 4.8 (without otlp exporter) runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 @@ -59,6 +59,29 @@ jobs: CC: /usr/bin/gcc-4.8 CXX: /usr/bin/g++-4.8 + cmake_gcc_48_otlp_exporter_test: + name: CMake gcc 4.8 (with otlp exporter) + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + - name: setup + run: | + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_gcc48.sh + - name: setup cmake + run: | + sudo CC=/usr/bin/gcc-4.8 CXX=/usr/bin/g++-4.8 ./ci/setup_cmake.sh + - name: setup grpc + run: | + sudo CC=/usr/bin/gcc-4.8 CXX=/usr/bin/g++-4.8 ./ci/setup_grpc.sh -v 4.8 + - name: run tests + run: ./ci/do_ci.sh cmake.legacy.exporter.otprotocol.test + env: + CC: /usr/bin/gcc-4.8 + CXX: /usr/bin/g++-4.8 + cmake_test_cxx20: name: CMake C++20 test runs-on: ubuntu-20.04 diff --git a/CMakeLists.txt b/CMakeLists.txt index 822e78bf37..8cbd374b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,14 @@ option(WITH_ELASTICSEARCH option(WITH_JAEGER "Whether to include the Jaeger exporter" OFF) +option(WITH_NO_GETENV "Whether the platform supports environment variables" OFF) + option(BUILD_TESTING "Whether to enable tests" ON) + +if(WITH_NO_GENENV) + add_definitions(-DNO_GETENV) +endif() + if(WIN32) add_definitions(-DNOMINMAX) if(BUILD_TESTING) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 483194c373..3c1be05119 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -92,6 +92,22 @@ elif [[ "$1" == "cmake.legacy.test" ]]; then make make test exit 0 +elif [[ "$1" == "cmake.legacy.exporter.otprotocol.test" ]]; then + cd "${BUILD_DIR}" + rm -rf * + export BUILD_ROOT="${BUILD_DIR}" + ${SRC_DIR}/tools/build-gtest.sh + ${SRC_DIR}/tools/build-benchmark.sh + cmake -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_CXX_STANDARD=11 \ + -DWITH_OTLP=ON \ + "${SRC_DIR}" + grpc_cpp_plugin=`which grpc_cpp_plugin` + proto_make_file="CMakeFiles/opentelemetry_proto.dir/build.make" + sed -i "s~gRPC_CPP_PLUGIN_EXECUTABLE-NOTFOUND~$grpc_cpp_plugin~" ${proto_make_file} #fixme + make -j $(nproc) + cd exporters/otlp && make test + exit 0 elif [[ "$1" == "cmake.exporter.otprotocol.test" ]]; then cd "${BUILD_DIR}" rm -rf * diff --git a/ci/setup_grpc.sh b/ci/setup_grpc.sh index 98780bb943..f6c1f9885a 100755 --- a/ci/setup_grpc.sh +++ b/ci/setup_grpc.sh @@ -5,7 +5,30 @@ set -e export DEBIAN_FRONTEND=noninteractive +old_grpc_version='v1.33.2' +new_grpc_version='v1.39.0' +gcc_version_for_new_grpc='5.1' +install_grpc_version=${new_grpc_version} +grpc_version='v1.39.0' +usage() { echo "Usage: $0 -v " 1>&2; exit 1; } +while getopts ":v:" o; do + case "${o}" in + v) + gcc_version=${OPTARG} + ;; + *) + usage + ;; + esac +done +if [ -z "${gcc_version}" ]; then + gcc_version=`gcc --version | awk '/gcc/ {print $NF}'` +fi +if [[ "${gcc_version}" < "${gcc_version_for_new_grpc}" ]]; then + echo "less" + install_grpc_version=${old_grpc_version} +fi if ! type cmake > /dev/null; then #cmake not installed, exiting exit 1 @@ -13,18 +36,26 @@ fi export BUILD_DIR=/tmp/ export INSTALL_DIR=/usr/local/ pushd $BUILD_DIR -git clone --depth=1 -b v1.34.0 https://github.com/grpc/grpc -cd grpc +echo "installing grpc version: ${install_grpc_version}" +git clone --depth=1 -b ${install_grpc_version} https://github.com/grpc/grpc +pushd grpc git submodule init git submodule update --depth 1 -mkdir -p cmake/build -pushd cmake/build +mkdir -p "third_party/abseil-cpp/build" && pushd "third_party/abseil-cpp/build" +cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR .. +make -j${nproc} install && popd +mkdir -p build && pushd build cmake -DgRPC_INSTALL=ON \ + -DCMAKE_CXX_STANDARD=11 \ -DgRPC_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - ../.. + -DCMAKE_PREFIX_PATH=$INSTALL_DIR \ + .. make -j $(nproc) make install popd popd + export PATH=${INSTALL_DIR}/bin:$PATH # ensure to use the installed grpc diff --git a/exporters/jaeger/src/udp_transport.cc b/exporters/jaeger/src/udp_transport.cc index 6ae41e7b9a..306a0e97fc 100644 --- a/exporters/jaeger/src/udp_transport.cc +++ b/exporters/jaeger/src/udp_transport.cc @@ -39,11 +39,11 @@ void UDPTransport::InitSocket() int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { - OTEL_INTERNAL_LOG_ERROR("Jaeger Exporter: WSAStartup failed with error: " << error); + OTEL_INTERNAL_LOG_ERROR("Jaeger Exporter: WSAStartup failed with error: " << err); return; } - /* Confirm that the WinSock DLL supports 2.2.*/ + /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ @@ -51,7 +51,9 @@ void UDPTransport::InitSocket() if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { - // TODO: handle error that WinSock 2.2 is not supported. + OTEL_INTERNAL_LOG_ERROR("Jaeger Exporter: winsock " << LOBYTE(wsaData.wVersion) << "." + << HIBYTE(wsaData.wVersion) + << " is not supported."); WSACleanup(); return; diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h index b3df30d259..31ad058c6d 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h @@ -11,26 +11,56 @@ #include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/common/env_variables.h" + OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter { namespace otlp { + +inline const std::string GetOtlpGrpcDefaultEndpoint() +{ + constexpr char kOtlpGrpcEndpointEnv[] = "OTEL_EXPORTER_OTLP_GRPC_ENDPOINT"; + constexpr char kOtlpGrpcEndpointDefault[] = "localhost:4317"; + + auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpGrpcEndpointEnv); + return endpoint.size() ? endpoint : kOtlpGrpcEndpointDefault; +} + +inline const bool GetOtlpGrpcDefaultIsSslEnable() +{ + constexpr char kOtlpGrpcIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE"; + auto ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpGrpcIsSslEnableEnv); + if (ssl_enable == "True" || ssl_enable == "TRUE" || ssl_enable == "true" || ssl_enable == "1") + { + return true; + } + return false; +} + +inline const std::string GetOtlpGrpcDefaultSslCertificate() +{ + constexpr char kOtlpGrpcSslCertificate[] = "OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE"; + auto ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpGrpcSslCertificate); + return ssl_cert.size() ? ssl_cert : ""; +} + /** * Struct to hold OTLP exporter options. */ struct OtlpGrpcExporterOptions { // The endpoint to export to. By default the OpenTelemetry Collector's default endpoint. - std::string endpoint = "localhost:4317"; + std::string endpoint = GetOtlpGrpcDefaultEndpoint(); // By default when false, uses grpc::InsecureChannelCredentials(); If true, // uses ssl_credentials_cacert_path if non-empty, else uses ssl_credentials_cacert_as_string - bool use_ssl_credentials = false; + bool use_ssl_credentials = GetOtlpGrpcDefaultIsSslEnable(); // ssl_credentials_cacert_path specifies path to .pem file to be used for SSL encryption. std::string ssl_credentials_cacert_path = ""; // ssl_credentials_cacert_as_string in-memory string representation of .pem file to be used for // SSL encryption. - std::string ssl_credentials_cacert_as_string = ""; + std::string ssl_credentials_cacert_as_string = GetOtlpGrpcDefaultSslCertificate(); }; /** diff --git a/exporters/otlp/test/otlp_grpc_exporter_test.cc b/exporters/otlp/test/otlp_grpc_exporter_test.cc index f7e82e6a46..13acd5b9ce 100644 --- a/exporters/otlp/test/otlp_grpc_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_exporter_test.cc @@ -129,6 +129,38 @@ TEST_F(OtlpGrpcExporterTestPeer, ConfigSslCredentialsTest) EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str); EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); } + +# ifndef NO_GETENV +// Test exporter configuration options with use_ssl_credentials +TEST_F(OtlpGrpcExporterTestPeer, ConfigFromEnv) +{ + const std::string cacert_str = "--begin and end fake cert--"; + const std::string cacert_env = "OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE=" + cacert_str; + putenv(const_cast(cacert_env.data())); + char ssl_enable_env[] = "OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE=True"; + putenv(ssl_enable_env); + const std::string endpoint = "http://localhost:9999"; + const std::string endpoint_env = "OTEL_EXPORTER_OTLP_GRPC_ENDPOINT=" + endpoint; + putenv(const_cast(endpoint_env.data())); + + std::unique_ptr exporter(new OtlpGrpcExporter()); + EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str); + EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); + EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); +# if defined(_MSC_VER) + putenv("OTEL_EXPORTER_OTLP_GRPC_ENDPOINT="); + putenv("OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE="); + putenv("OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE="); + +# else + unsetenv("OTEL_EXPORTER_OTLP_GRPC_ENDPOINT"); + unsetenv("OTEL_EXPORTER_OTLP_GRPC_SSL_CERTIFICATE"); + unsetenv("OTEL_EXPORTER_OTLP_GRPC_SSL_ENABLE"); + +# endif +} +# endif + } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h index 7e9321435c..ec3f562b19 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h @@ -5,6 +5,7 @@ #include "opentelemetry/ext/http/client/http_client_factory.h" #include "opentelemetry/ext/http/common/url_parser.h" +#include "opentelemetry/sdk/common/env_variables.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/span_data.h" @@ -21,23 +22,9 @@ inline const std::string GetDefaultZipkinEndpoint() const char *otel_exporter_zipkin_endpoint_env = "OTEL_EXPORTER_ZIPKIN_ENDPOINT"; const char *kZipkinEndpointDefault = "http://localhost:9411/api/v2/spans"; -#if defined(_MSC_VER) - // avoid calling std::getenv which is deprecated in MSVC. - size_t required_size = 0; - getenv_s(&required_size, nullptr, 0, otel_exporter_zipkin_endpoint_env); - const char *endpoint_from_env = nullptr; - std::unique_ptr endpoint_buffer; - if (required_size > 0) - { - endpoint_buffer = std::unique_ptr{new char[required_size]}; - getenv_s(&required_size, endpoint_buffer.get(), required_size, - otel_exporter_zipkin_endpoint_env); - endpoint_from_env = endpoint_buffer.get(); - } -#else - auto endpoint_from_env = std::getenv(otel_exporter_zipkin_endpoint_env); -#endif - return std::string{endpoint_from_env ? endpoint_from_env : kZipkinEndpointDefault}; + auto endpoint = + opentelemetry::sdk::common::GetEnvironmentVariable(otel_exporter_zipkin_endpoint_env); + return endpoint.size() ? endpoint : kZipkinEndpointDefault; } enum class TransportFormat diff --git a/sdk/include/opentelemetry/sdk/common/env_variables.h b/sdk/include/opentelemetry/sdk/common/env_variables.h new file mode 100644 index 0000000000..63d16d12b5 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/common/env_variables.h @@ -0,0 +1,40 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace common +{ + +// Returns the env variable set. +inline const std::string GetEnvironmentVariable(const char *env_var_name) +{ + const char *endpoint_from_env = nullptr; + +#ifndef NO_GETENV +# if defined(_MSC_VER) + // avoid calling std::getenv which is deprecated in MSVC. + size_t required_size = 0; + getenv_s(&required_size, nullptr, 0, env_var_name); + std::unique_ptr endpoint_buffer; + if (required_size > 0) + { + endpoint_buffer = std::unique_ptr{new char[required_size]}; + getenv_s(&required_size, endpoint_buffer.get(), required_size, env_var_name); + endpoint_from_env = endpoint_buffer.get(); + } +# else + endpoint_from_env = std::getenv(env_var_name); +# endif +#endif + return endpoint_from_env == nullptr ? std::string() : endpoint_from_env; +} +} // namespace common +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE \ No newline at end of file diff --git a/sdk/src/resource/resource_detector.cc b/sdk/src/resource/resource_detector.cc index 586de79738..c60056539b 100644 --- a/sdk/src/resource/resource_detector.cc +++ b/sdk/src/resource/resource_detector.cc @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/sdk/resource/resource_detector.h" -#include +#include "opentelemetry/sdk/common/env_variables.h" #include "opentelemetry/sdk/resource/resource.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -15,20 +15,12 @@ const char *OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; Resource OTELResourceDetector::Detect() noexcept { -#if defined(_MSC_VER) - size_t required_size = 0; - getenv_s(&required_size, nullptr, 0, OTEL_RESOURCE_ATTRIBUTES); - if (required_size == 0) - return Resource(); - std::unique_ptr attributes_buffer{new char[required_size]}; - getenv_s(&required_size, attributes_buffer.get(), required_size, OTEL_RESOURCE_ATTRIBUTES); - char *attributes_str = attributes_buffer.get(); -#else - char *attributes_str = std::getenv(OTEL_RESOURCE_ATTRIBUTES); - if (attributes_str == nullptr) + auto attributes_str = + opentelemetry::sdk::common::GetEnvironmentVariable(OTEL_RESOURCE_ATTRIBUTES); + if (attributes_str.size() == 0) + { return Resource(); -#endif - + } ResourceAttributes attributes; std::istringstream iss(attributes_str); std::string token; diff --git a/sdk/test/resource/resource_test.cc b/sdk/test/resource/resource_test.cc index 0c1a17d5e3..f426c23fe3 100644 --- a/sdk/test/resource/resource_test.cc +++ b/sdk/test/resource/resource_test.cc @@ -155,6 +155,7 @@ TEST(ResourceTest, MergeEmptyString) EXPECT_EQ(received_attributes.size(), expected_attributes.size()); } +#ifndef NO_GETENV TEST(ResourceTest, OtelResourceDetector) { std::map expected_attributes = {{"k", "v"}}; @@ -175,21 +176,21 @@ TEST(ResourceTest, OtelResourceDetector) } } EXPECT_EQ(received_attributes.size(), expected_attributes.size()); -#if defined(_MSC_VER) +# if defined(_MSC_VER) putenv("OTEL_RESOURCE_ATTRIBUTES="); -#else +# else unsetenv("OTEL_RESOURCE_ATTRIBUTES"); -#endif +# endif } TEST(ResourceTest, OtelResourceDetectorEmptyEnv) { std::map expected_attributes = {}; -#if defined(_MSC_VER) +# if defined(_MSC_VER) putenv("OTEL_RESOURCE_ATTRIBUTES="); -#else +# else unsetenv("OTEL_RESOURCE_ATTRIBUTES"); -#endif +# endif OTELResourceDetector detector; auto resource = detector.Detect(); auto received_attributes = resource.GetAttributes(); @@ -204,3 +205,4 @@ TEST(ResourceTest, OtelResourceDetectorEmptyEnv) } EXPECT_EQ(received_attributes.size(), expected_attributes.size()); } +#endif