Skip to content

Commit

Permalink
1. Add otlp_environment.h to maintain shared codes of `OtlpGrpcExpo…
Browse files Browse the repository at this point in the history
…rter` and `OtlpHttpExporter`

2. Add `timeout` and `metadata` options for `OtlpGrpcExporter`
3. Load environment variables `OTEL_EXPORTER_OTLP_TIMEOUT` , `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` , `OTEL_EXPORTER_OTLP_HEADERS` , `OTEL_EXPORTER_OTLP_TRACES_HEADERS` to initialize default options of `OtlpGrpcExporter` and `OtlpHttpExporter`
4. Load environment variables `OTEL_EXPORTER_OTLP_ENDPOINT` , `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` to initialize default options of `OtlpHttpExporter`

Signed-off-by: owentou <owentou@tencent.com>
  • Loading branch information
owent committed Sep 21, 2021
1 parent 74d4be4 commit 269ff8f
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 80 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Increment the:

## [Unreleased]

* Support environment variables for both `OtlpGrpcExporter` and `OtlpHttpExporter` ([#983](https://github.com/open-telemetry/opentelemetry-cpp/pull/983))

## [1.0.0] 2021-09-16

### API
Expand Down
2 changes: 2 additions & 0 deletions exporters/otlp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ cc_library(
"src/otlp_grpc_exporter.cc",
],
hdrs = [
"include/opentelemetry/exporters/otlp/otlp_environment.h",
"include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h",
"include/opentelemetry/exporters/otlp/protobuf_include_prefix.h",
"include/opentelemetry/exporters/otlp/protobuf_include_suffix.h",
Expand All @@ -61,6 +62,7 @@ cc_library(
"src/otlp_http_exporter.cc",
],
hdrs = [
"include/opentelemetry/exporters/otlp/otlp_environment.h",
"include/opentelemetry/exporters/otlp/otlp_http_exporter.h",
"include/opentelemetry/exporters/otlp/protobuf_include_prefix.h",
"include/opentelemetry/exporters/otlp/protobuf_include_suffix.h",
Expand Down
12 changes: 10 additions & 2 deletions exporters/otlp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,24 @@ auto exporter = std::unique_ptr<sdktrace::SpanExporter>(new otlp::OtlpHttpExport
| | `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE` | | |
| `ssl_credentials_cacert_as_string` | `OTEL_EXPORTER_OTLP_CERTIFICATE_STRING` | `""` | SSL Certifcate as in-memory string |
| | `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING` | | | |
| `timeout` | `OTEL_EXPORTER_OTLP_TIMEOUT` | `10s` | GRPC deadline |
| | `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | | |
| `metadata` | `OTEL_EXPORTER_OTLP_HEADERS` | | Custom metadata for GRPC |
| | `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | | |

### Configuration options ( OTLP HTTP Exporter )

| Option | Env Variable |Default | Description |
| ------------ |-----|------------ |------|
| `url` | n/a | `http://localhost:4317/v1/traces` | The OTLP HTTP endpoint to connect to |
| `url` | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317/v1/traces` | The OTLP HTTP endpoint to connect to |
| | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | | |
| `content_type` | n/a | `application/json` | Data format used - JSON or Binary |
| `json_bytes_mapping` | n/a | `JsonBytesMappingKind::kHexId` | Encoding used for trace_id and span_id |
| `use_json_name` | n/a | `false` | Whether to use json name of protobuf field to set the key of json |
| `timeout` | n/a | `30000 ms` | http timeout |
| `timeout` | `OTEL_EXPORTER_OTLP_TIMEOUT` | `10s` | http timeout |
| | `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | |
| `http_headers` | `OTEL_EXPORTER_OTLP_HEADERS` | | http headers |
| | `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | | |

## Example

Expand Down
203 changes: 203 additions & 0 deletions exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <algorithm>
#include <chrono>
#include <map>
#include <string>

#include "opentelemetry/nostd/string_view.h"

#include "opentelemetry/sdk/common/attribute_utils.h"
#include "opentelemetry/sdk/common/env_variables.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace otlp
{

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";

auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv);
if (endpoint.empty())
{
endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv);
}
return endpoint.size() ? endpoint : kOtlpEndpointDefault;
}

inline const std::string GetOtlpDefaultHttpEndpoint()
{
constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT";
constexpr char kOtlpEndpointDefault[] = "http://localhost:4317/v1/traces";

auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv);
if (endpoint.empty())
{
endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv);
}
return endpoint.size() ? endpoint : kOtlpEndpointDefault;
}

inline const 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;
}

inline const 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 : "";
}

inline const std::string GetOtlpDefaultSslCertificateString()
{
constexpr char kOtlpTracesSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING";
constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_TRACES_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 : "";
}

inline const std::chrono::system_clock::duration GetOtlpTimeoutFromString(const char *input)
{
if (nullptr == input || 0 == *input)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::seconds{10});
}

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');
}

opentelemetry::nostd::string_view unit{input};
if ("ns" == unit)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds{result});
}
else if ("us" == unit)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::microseconds{result});
}
else if ("ms" == unit)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::milliseconds{result});
}
else if ("m" == unit)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::minutes{result});
}
else if ("h" == unit)
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::hours{result});
}
else
{
return std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::seconds{result});
}
}

inline const std::chrono::system_clock::duration GetOtlpDefaultTimeout()
{
constexpr char kOtlpTracesTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT";
constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT";

auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesTimeoutEnv);
if (timeout.empty())
{
timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv);
}
return GetOtlpTimeoutFromString(timeout.c_str());
}

struct cmp_ic
{
bool operator()(const std::string &s1, const std::string &s2) const
{
return std::lexicographical_compare(
s1.begin(), s1.end(), s2.begin(), s2.end(),
[](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); });
}
};
using OtlpHeaders = std::multimap<std::string, std::string, cmp_ic>;

inline void DumpOtlpHeaders(OtlpHeaders &output, const char *env_var_name)
{
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)
{
output.emplace(std::make_pair((std::string)header_key, (std::string)header_value));
}
}
}

inline OtlpHeaders GetOtlpDefaultHeaders()
{
constexpr char kOtlpTracesHeadersEnv[] = "OTEL_EXPORTER_OTLP_TRACES_HEADERS";
constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS";

OtlpHeaders result;
DumpOtlpHeaders(result, kOtlpHeadersEnv);
DumpOtlpHeaders(result, kOtlpTracesHeadersEnv);
return result;
}

} // namespace otlp
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#pragma once

#include <chrono>

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

#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h"
Expand All @@ -11,78 +13,21 @@

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

#include "opentelemetry/sdk/common/env_variables.h"
#include "opentelemetry/exporters/otlp/otlp_environment.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace otlp
{

inline const std::string GetOtlpDefaultEndpoint()
{
constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT";
constexpr char kOtlpEndpointDefault[] = "http://localhost:4317";

auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv);
if (endpoint.size() == 0)
{
endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv);
}
return endpoint.size() ? endpoint : kOtlpEndpointDefault;
}

inline const 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.size() == 0)
{
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 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.size() == 0)
{
ssl_cert_path = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificate);
}
return ssl_cert_path.size() ? ssl_cert_path : "";
}

inline const std::string GetOtlpDefaultSslCertificateString()
{
constexpr char kOtlpTracesSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING";
constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING ";
auto ssl_cert =
opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificateString);
if (ssl_cert.size() == 0)
{
ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificateString);
}
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 = GetOtlpDefaultEndpoint();
std::string endpoint = GetOtlpDefaultGrpcEndpoint();
// 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 = GetOtlpDefaultIsSslEnable();
Expand All @@ -91,6 +36,10 @@ struct OtlpGrpcExporterOptions
// 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 = GetOtlpDefaultSslCertificateString();
// Timeout for grpc deadline
std::chrono::system_clock::duration timeout = GetOtlpDefaultTimeout();
// Additional HTTP headers
OtlpHeaders metadata = GetOtlpDefaultHeaders();
};

/**
Expand Down
Loading

0 comments on commit 269ff8f

Please sign in to comment.