diff --git a/CHANGELOG.md b/CHANGELOG.md index de2f099dce..a46f8c8ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ Increment the: * [SEMANTIC CONVENTIONS] Upgrade to version 1.18.0 [#1974](https://github.com/open-telemetry/opentelemetry-cpp/pull/1974) * Fix Prometheus server crash on listening to already used port [#1986](https://github.com/open-telemetry/opentelemetry-cpp/pull/1986) +* [EXPORTER] Boolean environment variables not parsed per the spec + [#1982](https://github.com/open-telemetry/opentelemetry-cpp/pull/1982) ## [1.8.2] 2023-01-31 diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index 32b247a054..98ae13ebb1 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -8,6 +8,7 @@ load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_library( name = "otlp_recordable", srcs = [ + "src/otlp_environment.cc", "src/otlp_log_recordable.cc", "src/otlp_metric_utils.cc", "src/otlp_populate_attribute_utils.cc", @@ -15,6 +16,7 @@ cc_library( "src/otlp_recordable_utils.cc", ], hdrs = [ + "include/opentelemetry/exporters/otlp/otlp_environment.h", "include/opentelemetry/exporters/otlp/otlp_log_recordable.h", "include/opentelemetry/exporters/otlp/otlp_metric_utils.h", "include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h", diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 49db6058ae..7e654d3a30 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -3,7 +3,7 @@ add_library( opentelemetry_otlp_recordable - src/otlp_log_recordable.cc src/otlp_recordable.cc + src/otlp_environment.cc src/otlp_log_recordable.cc src/otlp_recordable.cc src/otlp_populate_attribute_utils.cc src/otlp_recordable_utils.cc src/otlp_metric_utils.cc) set_target_properties(opentelemetry_otlp_recordable PROPERTIES EXPORT_NAME diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h index 27bd378b7c..e517f256b4 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h @@ -22,148 +22,91 @@ namespace exporter namespace otlp { -inline const std::string GetOtlpDefaultUserAgent() +inline std::string GetOtlpDefaultUserAgent() { return "OTel-OTLP-Exporter-Cpp/" OPENTELEMETRY_SDK_VERSION; } -inline const std::string GetOtlpDefaultGrpcEndpoint() -{ - constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4317"; +std::string GetOtlpDefaultGrpcTracesEndpoint(); +std::string GetOtlpDefaultGrpcMetricsEndpoint(); +std::string GetOtlpDefaultGrpcLogsEndpoint(); - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultGrpcEndpoint() +{ + return GetOtlpDefaultGrpcTracesEndpoint(); } -inline const std::string GetOtlpDefaultHttpEndpoint() +std::string GetOtlpDefaultHttpTracesEndpoint(); +std::string GetOtlpDefaultHttpMetricsEndpoint(); +std::string GetOtlpDefaultHttpLogsEndpoint(); + +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultHttpEndpoint() { - constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/traces"; + return GetOtlpDefaultHttpTracesEndpoint(); +} - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/traces"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultMetricsEndpoint() +{ + return GetOtlpDefaultHttpMetricsEndpoint(); } +bool GetOtlpDefaultTracesIsInsecure(); +bool GetOtlpDefaultMetricsIsInsecure(); +bool GetOtlpDefaultLogsIsInsecure(); + +// Compatibility with OTELCPP 1.8.2 inline bool GetOtlpDefaultIsSslEnable() { - constexpr char kOtlpTracesIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE"; - constexpr char kOtlpIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; - - auto ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesIsSslEnableEnv); - if (ssl_enable.empty()) - { - ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpIsSslEnableEnv); - } - if (ssl_enable == "True" || ssl_enable == "TRUE" || ssl_enable == "true" || ssl_enable == "1") - { - return true; - } - return false; + return (!GetOtlpDefaultTracesIsInsecure()); } -inline const std::string GetOtlpDefaultSslCertificatePath() +std::string GetOtlpDefaultTracesSslCertificatePath(); +std::string GetOtlpDefaultMetricsSslCertificatePath(); +std::string GetOtlpDefaultLogsSslCertificatePath(); + +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultSslCertificatePath() { - constexpr char kOtlpTracesSslCertificate[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"; - constexpr char kOtlpSslCertificate[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; - auto ssl_cert_path = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificate); - if (ssl_cert_path.empty()) - { - ssl_cert_path = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificate); - } - return ssl_cert_path.size() ? ssl_cert_path : ""; + return GetOtlpDefaultTracesSslCertificatePath(); } -inline const std::string GetOtlpDefaultSslCertificateString() +std::string GetOtlpDefaultTracesSslCertificateString(); +std::string GetOtlpDefaultMetricsSslCertificateString(); +std::string GetOtlpDefaultLogsSslCertificateString(); + +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultSslCertificateString() { - constexpr char kOtlpTracesSslCertificateString[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING"; - constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; - auto ssl_cert = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificateString); - if (ssl_cert.empty()) - { - ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificateString); - } - return ssl_cert.size() ? ssl_cert : ""; + return GetOtlpDefaultTracesSslCertificateString(); } -inline const std::chrono::system_clock::duration GetOtlpTimeoutFromString(const char *input) -{ - if (nullptr == input || 0 == *input) - { - return std::chrono::duration_cast( - std::chrono::seconds{10}); - } +std::string GetOtlpDefaultTracesSslClientKeyPath(); +std::string GetOtlpDefaultMetricsSslClientKeyPath(); +std::string GetOtlpDefaultLogsSslClientKeyPath(); - std::chrono::system_clock::duration::rep result = 0; - // Skip spaces - for (; *input && (' ' == *input || '\t' == *input || '\r' == *input || '\n' == *input); ++input) - ; +std::string GetOtlpDefaultTracesSslClientKeyString(); +std::string GetOtlpDefaultMetricsSslClientKeyString(); +std::string GetOtlpDefaultLogsSslClientKeyString(); - for (; *input && (*input >= '0' && *input <= '9'); ++input) - { - result = result * 10 + (*input - '0'); - } +std::string GetOtlpDefaultTracesSslClientCertificatePath(); +std::string GetOtlpDefaultMetricsSslClientCertificatePath(); +std::string GetOtlpDefaultLogsSslClientCertificatePath(); - opentelemetry::nostd::string_view unit{input}; - if ("ns" == unit) - { - return std::chrono::duration_cast( - std::chrono::nanoseconds{result}); - } - else if ("us" == unit) - { - return std::chrono::duration_cast( - std::chrono::microseconds{result}); - } - else if ("ms" == unit) - { - return std::chrono::duration_cast( - std::chrono::milliseconds{result}); - } - else if ("m" == unit) - { - return std::chrono::duration_cast( - std::chrono::minutes{result}); - } - else if ("h" == unit) - { - return std::chrono::duration_cast( - std::chrono::hours{result}); - } - else - { - return std::chrono::duration_cast( - std::chrono::seconds{result}); - } -} +std::string GetOtlpDefaultTracesSslClientCertificateString(); +std::string GetOtlpDefaultMetricsSslClientCertificateString(); +std::string GetOtlpDefaultLogsSslClientCertificateString(); -inline const std::chrono::system_clock::duration GetOtlpDefaultTimeout() -{ - constexpr char kOtlpTracesTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; +std::chrono::system_clock::duration GetOtlpDefaultTracesTimeout(); +std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout(); +std::chrono::system_clock::duration GetOtlpDefaultLogsTimeout(); - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); +// Compatibility with OTELCPP 1.8.2 +inline std::chrono::system_clock::duration GetOtlpDefaultTimeout() +{ + return GetOtlpDefaultTracesTimeout(); } struct cmp_ic @@ -177,191 +120,14 @@ struct cmp_ic }; using OtlpHeaders = std::multimap; -inline void DumpOtlpHeaders(OtlpHeaders &output, - const char *env_var_name, - std::unordered_set &remove_cache) -{ - auto value = opentelemetry::sdk::common::GetEnvironmentVariable(env_var_name); - if (value.empty()) - { - return; - } - - opentelemetry::common::KeyValueStringTokenizer tokenizer{value}; - opentelemetry::nostd::string_view header_key; - opentelemetry::nostd::string_view header_value; - bool header_valid = true; - - while (tokenizer.next(header_valid, header_key, header_value)) - { - if (header_valid) - { - std::string key = static_cast(header_key); - if (remove_cache.end() == remove_cache.find(key)) - { - remove_cache.insert(key); - auto range = output.equal_range(key); - if (range.first != range.second) - { - output.erase(range.first, range.second); - } - } - - output.emplace(std::make_pair(std::move(key), static_cast(header_value))); - } - } -} +OtlpHeaders GetOtlpDefaultTracesHeaders(); +OtlpHeaders GetOtlpDefaultMetricsHeaders(); +OtlpHeaders GetOtlpDefaultLogsHeaders(); +// Compatibility with OTELCPP 1.8.2 inline OtlpHeaders GetOtlpDefaultHeaders() { - constexpr char kOtlpTracesHeadersEnv[] = "OTEL_EXPORTER_OTLP_TRACES_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; - - OtlpHeaders result; - std::unordered_set trace_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, trace_remove_cache); - - trace_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpTracesHeadersEnv, trace_remove_cache); - - return result; -} - -inline const std::string GetOtlpDefaultHttpLogEndpoint() -{ - constexpr char kOtlpLogsEndpointEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/logs"; - - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpLogsEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/logs"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; -} - -inline const std::chrono::system_clock::duration GetOtlpDefaultLogTimeout() -{ - constexpr char kOtlpLogsTimeoutEnv[] = "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; - - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpLogsTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); -} - -inline OtlpHeaders GetOtlpDefaultLogHeaders() -{ - constexpr char kOtlpLogsHeadersEnv[] = "OTEL_EXPORTER_OTLP_LOGS_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; - - OtlpHeaders result; - std::unordered_set log_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, log_remove_cache); - - log_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpLogsHeadersEnv, log_remove_cache); - - return result; -} - -// --- Metrics Environment Variables -inline const std::string GetOtlpDefaultMetricsEndpoint() -{ - constexpr char kOtlpMetricsEndpointEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/metrics"; - - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/metrics"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; -} - -inline const std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout() -{ - constexpr char kOtlpMetricsTimeoutEnv[] = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; - - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); -} - -inline OtlpHeaders GetOtlpDefaultMetricsHeaders() -{ - constexpr char kOtlpMetricsHeadersEnv[] = "OTEL_EXPORTER_OTLP_METRICS_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; - - OtlpHeaders result; - std::unordered_set metric_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, metric_remove_cache); - - metric_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpMetricsHeadersEnv, metric_remove_cache); - - return result; -} - -inline bool GetOtlpDefaultMetricsIsSslEnable() -{ - constexpr char kOtlpMetricsIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_METRICS_SSL_ENABLE"; - constexpr char kOtlpIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; - - auto ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsIsSslEnableEnv); - if (ssl_enable.empty()) - { - ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpIsSslEnableEnv); - } - if (ssl_enable == "True" || ssl_enable == "TRUE" || ssl_enable == "true" || ssl_enable == "1") - { - return true; - } - return false; -} - -inline const std::string GetOtlpDefaultMetricsSslCertificatePath() -{ - constexpr char kOtlpMetricsSslCertificate[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE"; - constexpr char kOtlpSslCertificate[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; - auto ssl_cert_path = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsSslCertificate); - if (ssl_cert_path.empty()) - { - ssl_cert_path = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificate); - } - return ssl_cert_path.size() ? ssl_cert_path : ""; -} - -inline const std::string GetOtlpDefaultMetricsSslCertificateString() -{ - constexpr char kOtlpTracesSslCertificateString[] = - "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE_STRING"; - constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; - auto ssl_cert = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificateString); - if (ssl_cert.empty()) - { - ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificateString); - } - return ssl_cert.size() ? ssl_cert : ""; + return GetOtlpDefaultTracesHeaders(); } } // namespace otlp diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h index 4cc3236da8..cb26758f9d 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h @@ -64,10 +64,10 @@ struct OtlpHttpClientOptions bool console_debug = false; // TODO: Enable/disable to verify SSL certificate - std::chrono::system_clock::duration timeout = GetOtlpDefaultTimeout(); + std::chrono::system_clock::duration timeout; // Additional HTTP headers - OtlpHeaders http_headers = GetOtlpDefaultHeaders(); + OtlpHeaders http_headers; // Concurrent requests std::size_t max_concurrent_requests = 64; @@ -76,7 +76,7 @@ struct OtlpHttpClientOptions std::size_t max_requests_per_connection = 8; // User agent - std::string user_agent = GetOtlpDefaultUserAgent(); + std::string user_agent; inline OtlpHttpClientOptions(nostd::string_view input_url, HttpRequestContentType input_content_type, diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h index 4ad5d82005..37f97e8232 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h @@ -28,7 +28,7 @@ struct OtlpHttpLogRecordExporterOptions // @see // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md // @see https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver/otlpreceiver - std::string url = GetOtlpDefaultHttpLogEndpoint(); + std::string url = GetOtlpDefaultHttpLogsEndpoint(); // By default, post json data HttpRequestContentType content_type = HttpRequestContentType::kJson; @@ -45,10 +45,10 @@ struct OtlpHttpLogRecordExporterOptions bool console_debug = false; // TODO: Enable/disable to verify SSL certificate - std::chrono::system_clock::duration timeout = GetOtlpDefaultLogTimeout(); + std::chrono::system_clock::duration timeout = GetOtlpDefaultLogsTimeout(); // Additional HTTP headers - OtlpHeaders http_headers = GetOtlpDefaultLogHeaders(); + OtlpHeaders http_headers = GetOtlpDefaultLogsHeaders(); # ifdef ENABLE_ASYNC_EXPORT // Concurrent requests diff --git a/exporters/otlp/src/otlp_environment.cc b/exporters/otlp/src/otlp_environment.cc new file mode 100644 index 0000000000..f47d7c3720 --- /dev/null +++ b/exporters/otlp/src/otlp_environment.cc @@ -0,0 +1,750 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_environment.h" + +#include "opentelemetry/sdk/common/env_variables.h" +#include "opentelemetry/sdk/version/version.h" + +#include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/sdk_config.h" + +namespace nostd = opentelemetry::nostd; +namespace sdk_common = opentelemetry::sdk::common; + +/* + TODO: + - Document new variables + - Announce deprecation in CHANGELOG + - Activate deprecation warning +*/ +/* #define WARN_DEPRECATED_ENV */ + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +static bool GetBoolDualEnvVar(const char *signal_name, const char *generic_name, bool &value) +{ + bool exists; + + exists = sdk_common::GetBoolEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetBoolEnvironmentVariable(generic_name, value); + + return exists; +} + +static bool GetDurationDualEnvVar(const char *signal_name, + const char *generic_name, + std::chrono::system_clock::duration &value) +{ + bool exists; + + exists = sdk_common::GetDurationEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetDurationEnvironmentVariable(generic_name, value); + + return exists; +} + +static bool GetStringDualEnvVar(const char *signal_name, + const char *generic_name, + std::string &value) +{ + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetStringEnvironmentVariable(generic_name, value); + + return exists; +} + +std::string GetOtlpDefaultGrpcTracesEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultGrpcMetricsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultGrpcLogsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpTracesEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/traces"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/traces"; + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpMetricsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/metrics"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/metrics"; + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpLogsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/logs"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/logs"; + return value; + } + + return kDefault; +} + +bool GetOtlpDefaultTracesIsInsecure() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + constexpr char kOldSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE"; + constexpr char kOldGenericEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; + + bool insecure; + bool ssl_enabled; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldSignalEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldSignalEnv << "> is deprecated, use <" + << kSignalEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldGenericEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldGenericEnv << "> is deprecated, use <" + << kGenericEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + return false; +} + +bool GetOtlpDefaultMetricsIsInsecure() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + constexpr char kOldSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_SSL_ENABLE"; + constexpr char kOldGenericEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; + + bool insecure; + bool ssl_enabled; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldSignalEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldSignalEnv << "> is deprecated, use <" + << kSignalEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldGenericEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldGenericEnv << "> is deprecated, use <" + << kGenericEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + return false; +} + +bool GetOtlpDefaultLogsIsInsecure() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + + bool insecure; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + return false; +} + +std::string GetOtlpDefaultTracesSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::chrono::system_clock::duration GetOtlpDefaultTracesTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +std::chrono::system_clock::duration GetOtlpDefaultLogsTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +static void DumpOtlpHeaders(OtlpHeaders &output, const char *env_var_name) +{ + std::string raw_value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(env_var_name, raw_value); + + if (!exists) + { + return; + } + + opentelemetry::common::KeyValueStringTokenizer tokenizer{raw_value}; + opentelemetry::nostd::string_view header_key; + opentelemetry::nostd::string_view header_value; + bool header_valid = true; + + std::unordered_set remove_cache; + + while (tokenizer.next(header_valid, header_key, header_value)) + { + if (header_valid) + { + std::string key(header_key); + if (remove_cache.end() == remove_cache.find(key)) + { + remove_cache.insert(key); + auto range = output.equal_range(key); + if (range.first != range.second) + { + output.erase(range.first, range.second); + } + } + + std::string value(header_value); + output.emplace(std::make_pair(std::move(key), std::move(value))); + } + } +} + +static OtlpHeaders GetHeaders(const char *signal_name, const char *generic_name) +{ + OtlpHeaders result; + DumpOtlpHeaders(result, generic_name); + DumpOtlpHeaders(result, signal_name); + + return result; +} + +OtlpHeaders GetOtlpDefaultTracesHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +OtlpHeaders GetOtlpDefaultMetricsHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +OtlpHeaders GetOtlpDefaultLogsHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/test/otlp_http_exporter_test.cc b/exporters/otlp/test/otlp_http_exporter_test.cc index d7d53d5839..71e3496a92 100644 --- a/exporters/otlp/test/otlp_http_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_exporter_test.cc @@ -557,7 +557,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) { const std::string url = "http://localhost:9999/v1/traces"; setenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT", "1eternity", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "k1=v3,k1=v4", 1); @@ -565,7 +565,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) EXPECT_EQ(GetOptions(exporter).url, url); EXPECT_EQ( GetOptions(exporter).timeout.count(), - std::chrono::duration_cast(std::chrono::seconds{20}) + std::chrono::duration_cast(std::chrono::seconds{10}) .count()); EXPECT_EQ(GetOptions(exporter).http_headers.size(), 3); { @@ -588,7 +588,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) } unsetenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS"); } diff --git a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc index 627a2d5f0e..4df827238d 100644 --- a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc @@ -616,7 +616,7 @@ TEST_F(OtlpHttpLogRecordExporterTestPeer, ConfigFromLogsEnv) { const std::string url = "http://localhost:9999/v1/logs"; setenv("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT", "20s", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_LOGS_HEADERS", "k1=v3,k1=v4", 1); @@ -647,14 +647,14 @@ TEST_F(OtlpHttpLogRecordExporterTestPeer, ConfigFromLogsEnv) } unsetenv("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_LOGS_HEADERS"); } TEST_F(OtlpHttpLogRecordExporterTestPeer, DefaultEndpoint) { - EXPECT_EQ("http://localhost:4318/v1/logs", GetOtlpDefaultHttpLogEndpoint()); + EXPECT_EQ("http://localhost:4318/v1/logs", GetOtlpDefaultHttpLogsEndpoint()); EXPECT_EQ("http://localhost:4318/v1/traces", GetOtlpDefaultHttpEndpoint()); EXPECT_EQ("http://localhost:4317", GetOtlpDefaultGrpcEndpoint()); } diff --git a/exporters/otlp/test/otlp_http_metric_exporter_test.cc b/exporters/otlp/test/otlp_http_metric_exporter_test.cc index 54abb88511..c753589047 100644 --- a/exporters/otlp/test/otlp_http_metric_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_metric_exporter_test.cc @@ -895,7 +895,7 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ConfigFromMetricsEnv) { const std::string url = "http://localhost:9999/v1/metrics"; setenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT", "20s", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_METRICS_HEADERS", "k1=v3,k1=v4", 1); @@ -926,7 +926,7 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ConfigFromMetricsEnv) } unsetenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_METRICS_HEADERS"); } diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h index b3baebde70..fe3c603e8a 100644 --- a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h @@ -33,8 +33,11 @@ inline const std::string GetPrometheusDefaultHttpEndpoint() constexpr char kPrometheusEndpointEnv[] = "PROMETHEUS_EXPORTER_ENDPOINT"; constexpr char kPrometheusEndpointDefault[] = "localhost:9464"; - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kPrometheusEndpointEnv); - return endpoint.size() ? endpoint : kPrometheusEndpointDefault; + std::string endpoint; + + auto exists = + opentelemetry::sdk::common::GetStringEnvironmentVariable(kPrometheusEndpointEnv, endpoint); + return exists ? endpoint : kPrometheusEndpointDefault; } /** diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h index 299a5db4ed..f5ee941d22 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h @@ -18,9 +18,11 @@ 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"; - auto endpoint = - opentelemetry::sdk::common::GetEnvironmentVariable(otel_exporter_zipkin_endpoint_env); - return endpoint.size() ? endpoint : kZipkinEndpointDefault; + std::string endpoint; + + auto exists = opentelemetry::sdk::common::GetStringEnvironmentVariable( + otel_exporter_zipkin_endpoint_env, endpoint); + return exists ? endpoint : kZipkinEndpointDefault; } enum class TransportFormat diff --git a/ext/test/http/CMakeLists.txt b/ext/test/http/CMakeLists.txt index 268c91cbf2..3ce72b3b83 100644 --- a/ext/test/http/CMakeLists.txt +++ b/ext/test/http/CMakeLists.txt @@ -10,11 +10,11 @@ if(WITH_HTTP_CLIENT_CURL) if(TARGET CURL::libcurl) target_link_libraries(${FILENAME} opentelemetry_http_client_curl - CURL::libcurl) + opentelemetry_common CURL::libcurl) else() include_directories(${CURL_INCLUDE_DIRS}) target_link_libraries(${FILENAME} ${CURL_LIBRARIES} - opentelemetry_http_client_curl) + opentelemetry_http_client_curl opentelemetry_common) endif() gtest_add_tests( TARGET ${FILENAME} diff --git a/sdk/include/opentelemetry/sdk/common/env_variables.h b/sdk/include/opentelemetry/sdk/common/env_variables.h index b1e81e7fd8..a02a66c29e 100644 --- a/sdk/include/opentelemetry/sdk/common/env_variables.h +++ b/sdk/include/opentelemetry/sdk/common/env_variables.h @@ -3,7 +3,9 @@ #pragma once +#include #include + #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -12,6 +14,31 @@ namespace sdk namespace common { +/** + Read a boolean environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetBoolEnvironmentVariable(const char *env_var_name, bool &value); + +/** + Read a duration environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetDurationEnvironmentVariable(const char *env_var_name, + std::chrono::system_clock::duration &value); + +/** + Read a string environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetStringEnvironmentVariable(const char *env_var_name, std::string &value); + #if defined(_MSC_VER) inline int setenv(const char *name, const char *value, int) { @@ -24,30 +51,6 @@ inline int unsetenv(const char *name) } #endif -// Returns the env variable set. -inline const std::string GetEnvironmentVariable(const char *env_var_name) -{ -#if !defined(NO_GETENV) - const char *endpoint_from_env = nullptr; -# 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 // defined(_MSC_VER) - return endpoint_from_env == nullptr ? std::string{} : std::string{endpoint_from_env}; -#else - return std::string{}; -#endif // !defined(NO_GETENV) -} } // namespace common } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/common/BUILD b/sdk/src/common/BUILD index cd648c8a16..cdbd1955f3 100644 --- a/sdk/src/common/BUILD +++ b/sdk/src/common/BUILD @@ -21,6 +21,18 @@ cc_library( ], ) +cc_library( + name = "env_variables", + srcs = [ + "env_variables.cc", + ], + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/common:global_log_handler", + ], +) + cc_library( name = "global_log_handler", srcs = [ diff --git a/sdk/src/common/CMakeLists.txt b/sdk/src/common/CMakeLists.txt index b4364372d1..4caf9e048c 100644 --- a/sdk/src/common/CMakeLists.txt +++ b/sdk/src/common/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -set(COMMON_SRCS random.cc core.cc global_log_handler.cc) +set(COMMON_SRCS random.cc core.cc global_log_handler.cc env_variables.cc) if(WIN32) list(APPEND COMMON_SRCS platform/fork_windows.cc) else() diff --git a/sdk/src/common/env_variables.cc b/sdk/src/common/env_variables.cc new file mode 100644 index 0000000000..a3f50b15ba --- /dev/null +++ b/sdk/src/common/env_variables.cc @@ -0,0 +1,196 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/env_variables.h" + +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif + +#include + +#include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace common +{ + +bool GetRawEnvironmentVariable(const char *env_var_name, std::string &value) +{ +#if !defined(NO_GETENV) + const char *endpoint_from_env = nullptr; +# 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 // defined(_MSC_VER) + + if (endpoint_from_env != nullptr) + { + value = std::string{endpoint_from_env}; + return true; + } + + value = std::string{}; + return false; +#else + value = std::string{}; + return false; +#endif // !defined(NO_GETENV) +} + +bool GetBoolEnvironmentVariable(const char *env_var_name, bool &value) +{ + std::string raw_value; + bool exists = GetRawEnvironmentVariable(env_var_name, raw_value); + if (!exists || raw_value.empty()) + { + value = false; + return false; + } + + if (strcasecmp(raw_value.c_str(), "true") == 0) + { + value = true; + return true; + } + + if (strcasecmp(raw_value.c_str(), "false") == 0) + { + value = false; + return true; + } + + OTEL_INTERNAL_LOG_WARN("Environment variable <" << env_var_name << "> has an invalid value <" + << raw_value << ">, defaulting to false"); + value = false; + return true; +} + +static bool GetTimeoutFromString(const char *input, std::chrono::system_clock::duration &value) +{ + std::chrono::system_clock::duration::rep result = 0; + + // Skip spaces + for (; *input && (' ' == *input || '\t' == *input || '\r' == *input || '\n' == *input); ++input) + ; + + for (; *input && (*input >= '0' && *input <= '9'); ++input) + { + result = result * 10 + (*input - '0'); + } + + if (result == 0) + { + // Rejecting duration 0 as invalid. + return false; + } + + opentelemetry::nostd::string_view unit{input}; + + if (unit == "ns") + { + value = std::chrono::duration_cast( + std::chrono::nanoseconds{result}); + return true; + } + + if (unit == "us") + { + value = std::chrono::duration_cast( + std::chrono::microseconds{result}); + return true; + } + + if (unit == "ms") + { + value = std::chrono::duration_cast( + std::chrono::milliseconds{result}); + return true; + } + + if (unit == "s") + { + value = std::chrono::duration_cast( + std::chrono::seconds{result}); + return true; + } + + if (unit == "m") + { + value = std::chrono::duration_cast( + std::chrono::minutes{result}); + return true; + } + + if (unit == "h") + { + value = + std::chrono::duration_cast(std::chrono::hours{result}); + return true; + } + + if (unit == "") + { + // TODO: The spec says milliseconds, but opentelemetry-cpp implemented + // seconds by default. Fixing this is a breaking change. + + value = std::chrono::duration_cast( + std::chrono::seconds{result}); + return true; + } + + // Failed to parse the input string. + return false; +} + +bool GetDurationEnvironmentVariable(const char *env_var_name, + std::chrono::system_clock::duration &value) +{ + std::string raw_value; + bool exists = GetRawEnvironmentVariable(env_var_name, raw_value); + if (!exists || raw_value.empty()) + { + value = + std::chrono::duration_cast(std::chrono::seconds{0}); + return false; + } + + exists = GetTimeoutFromString(raw_value.c_str(), value); + + if (!exists) + { + OTEL_INTERNAL_LOG_WARN("Environment variable <" << env_var_name << "> has an invalid value <" + << raw_value << ">, ignoring"); + } + return exists; +} + +bool GetStringEnvironmentVariable(const char *env_var_name, std::string &value) +{ + bool exists = GetRawEnvironmentVariable(env_var_name, value); + if (!exists || value.empty()) + { + return false; + } + return true; +} + +} // namespace common +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/resource/BUILD b/sdk/src/resource/BUILD index f17822979d..6cff52723a 100644 --- a/sdk/src/resource/BUILD +++ b/sdk/src/resource/BUILD @@ -11,5 +11,6 @@ cc_library( deps = [ "//api", "//sdk:headers", + "//sdk/src/common:env_variables", ], ) diff --git a/sdk/src/resource/resource_detector.cc b/sdk/src/resource/resource_detector.cc index c60056539b..f5c856f088 100644 --- a/sdk/src/resource/resource_detector.cc +++ b/sdk/src/resource/resource_detector.cc @@ -15,9 +15,12 @@ const char *OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; Resource OTELResourceDetector::Detect() noexcept { - auto attributes_str = - opentelemetry::sdk::common::GetEnvironmentVariable(OTEL_RESOURCE_ATTRIBUTES); - if (attributes_str.size() == 0) + std::string attributes_str; + bool exists; + + exists = opentelemetry::sdk::common::GetStringEnvironmentVariable(OTEL_RESOURCE_ATTRIBUTES, + attributes_str); + if (!exists) { return Resource(); } diff --git a/sdk/test/common/BUILD b/sdk/test/common/BUILD index 95a6737b14..0f886ec569 100644 --- a/sdk/test/common/BUILD +++ b/sdk/test/common/BUILD @@ -163,3 +163,15 @@ otel_cc_benchmark( "//sdk:headers", ], ) + +cc_test( + name = "env_var_test", + srcs = [ + "env_var_test.cc", + ], + tags = ["test"], + deps = [ + "//sdk/src/common:env_variables", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/common/CMakeLists.txt b/sdk/test/common/CMakeLists.txt index ddf95e79d4..0205061911 100644 --- a/sdk/test/common/CMakeLists.txt +++ b/sdk/test/common/CMakeLists.txt @@ -10,7 +10,8 @@ foreach( circular_buffer_test attribute_utils_test attributemap_hash_test - global_log_handle_test) + global_log_handle_test + env_var_test) add_executable(${testname} "${testname}.cc") target_link_libraries( diff --git a/sdk/test/common/env_var_test.cc b/sdk/test/common/env_var_test.cc new file mode 100644 index 0000000000..23d3802361 --- /dev/null +++ b/sdk/test/common/env_var_test.cc @@ -0,0 +1,210 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/env_variables.h" + +#include + +#if defined(_MSC_VER) +using opentelemetry::sdk::common::setenv; +using opentelemetry::sdk::common::unsetenv; +#endif + +using opentelemetry::sdk::common::GetBoolEnvironmentVariable; +using opentelemetry::sdk::common::GetDurationEnvironmentVariable; +using opentelemetry::sdk::common::GetStringEnvironmentVariable; + +#ifndef NO_GETENV +TEST(EnvVarTest, BoolEnvVar) +{ + unsetenv("BOOL_ENV_VAR_NONE"); + setenv("BOOL_ENV_VAR_EMPTY", "", 1); + setenv("BOOL_ENV_VAR_T1", "true", 1); + setenv("BOOL_ENV_VAR_T2", "TRUE", 1); + setenv("BOOL_ENV_VAR_T3", "TrUe", 1); + setenv("BOOL_ENV_VAR_F1", "false", 1); + setenv("BOOL_ENV_VAR_F2", "FALSE", 1); + setenv("BOOL_ENV_VAR_F3", "FaLsE", 1); + setenv("BOOL_ENV_VAR_BROKEN", "Maybe ?", 1); + + bool exists; + bool value = true; + + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + EXPECT_FALSE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T1", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T2", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T3", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F1", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F2", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F3", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + // This raises a warning, not verifying the warning text. + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_BROKEN", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + unsetenv("BOOL_ENV_VAR_EMPTY"); + unsetenv("BOOL_ENV_VAR_T1"); + unsetenv("BOOL_ENV_VAR_T2"); + unsetenv("BOOL_ENV_VAR_T3"); + unsetenv("BOOL_ENV_VAR_F1"); + unsetenv("BOOL_ENV_VAR_F2"); + unsetenv("BOOL_ENV_VAR_F3"); + unsetenv("BOOL_ENV_VAR_BROKEN"); +} + +TEST(EnvVarTest, StringEnvVar) +{ + unsetenv("STRING_ENV_VAR_NONE"); + setenv("STRING_ENV_VAR_EMPTY", "", 1); + setenv("STRING_ENV_VAR", "my string", 1); + + bool exists; + std::string value; + + exists = GetStringEnvironmentVariable("STRING_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + exists = GetStringEnvironmentVariable("STRING_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + EXPECT_EQ(value, ""); + + value = "poison"; + exists = GetStringEnvironmentVariable("STRING_ENV_VAR", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, "my string"); + + unsetenv("STRING_ENV_VAR_EMPTY"); + unsetenv("STRING_ENV_VAR"); +} + +TEST(EnvVarTest, DurationEnvVar) +{ + unsetenv("DURATION_ENV_VAR_NONE"); + setenv("DURATION_ENV_VAR_EMPTY", "", 1); + setenv("DURATION_ENV_VAR_1", "10ns", 1); + setenv("DURATION_ENV_VAR_2", "20us", 1); + setenv("DURATION_ENV_VAR_3", "30ms", 1); + setenv("DURATION_ENV_VAR_4", "40s", 1); + setenv("DURATION_ENV_VAR_5", "50m", 1); + setenv("DURATION_ENV_VAR_6", "60h", 1); + setenv("DURATION_ENV_VAR_7", "123", 1); + setenv("DURATION_ENV_VAR_BROKEN_1", "123 ms", 1); + setenv("DURATION_ENV_VAR_BROKEN_2", "1mississippi", 1); + + bool exists; + std::chrono::system_clock::duration poison; + std::chrono::system_clock::duration value; + std::chrono::system_clock::duration expected; + + poison = + std::chrono::duration_cast(std::chrono::seconds{666}); + + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::nanoseconds{10}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_1", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = std::chrono::duration_cast( + std::chrono::microseconds{20}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_2", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = std::chrono::duration_cast( + std::chrono::milliseconds{30}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_3", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::seconds{40}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_4", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::minutes{50}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_5", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::hours{60}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_6", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + // Deviation from the spec: 123 seconds instead of 123 milliseconds + expected = + std::chrono::duration_cast(std::chrono::seconds{123}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_7", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + // This raises a warning, not verifying the warning text. + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_BROKEN_1", value); + EXPECT_FALSE(exists); + + // This raises a warning, not verifying the warning text. + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_BROKEN_2", value); + EXPECT_FALSE(exists); + + unsetenv("STRING_ENV_VAR_EMPTY"); + unsetenv("STRING_ENV_VAR_1"); + unsetenv("STRING_ENV_VAR_2"); + unsetenv("STRING_ENV_VAR_3"); + unsetenv("STRING_ENV_VAR_4"); + unsetenv("STRING_ENV_VAR_5"); + unsetenv("STRING_ENV_VAR_6"); + unsetenv("STRING_ENV_VAR_7"); + unsetenv("STRING_ENV_VAR_BROKEN_1"); + unsetenv("STRING_ENV_VAR_BROKEN_2"); +} + +#endif