Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ Increment the:

## [Unreleased]

* [SDK] Read span limits from the environment variables defined in the
specification (OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT,
OTEL_SPAN_LINK_COUNT_LIMIT, ...) in the TracerProviderFactory overloads
that do not receive explicit SpanLimits
[#4258](https://github.com/open-telemetry/opentelemetry-cpp/pull/4258)

* docs: update supported development platforms
[#4260](https://github.com/open-telemetry/opentelemetry-cpp/pull/4260)

Expand Down
18 changes: 18 additions & 0 deletions sdk/include/opentelemetry/sdk/trace/span_limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ struct SpanLimits
}
};

namespace span_limits_env
{

/**
* @brief Returns span limits read from the environment variables defined in the
* OpenTelemetry specification
* (https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits).
*
* A field whose environment variable is not set keeps its SpanLimits::NoLimits() value, so with
* no variables set the result equals SpanLimits::NoLimits() and SDK behavior is unchanged. The
* span-specific variables (OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
* OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT) take precedence over the general ones
* (OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, OTEL_ATTRIBUTE_COUNT_LIMIT).
*/
OPENTELEMETRY_EXPORT SpanLimits GetSpanLimitsFromEnv();

} // namespace span_limits_env

} // namespace trace
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
1 change: 1 addition & 0 deletions sdk/src/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_library(
batch_span_processor_options.cc
simple_processor_factory.cc
span_data.cc
span_limits.cc
samplers/always_on_factory.cc
samplers/always_off_factory.cc
samplers/parent.cc
Expand Down
75 changes: 75 additions & 0 deletions sdk/src/trace/span_limits.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include <cstddef>
#include <cstdint>

#include "opentelemetry/sdk/common/env_variables.h"
#include "opentelemetry/sdk/trace/span_limits.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace trace
{
namespace span_limits_env
{

// Environment variable names, see
// https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits
static constexpr const char *kAttributeValueLengthLimitEnv = "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT";
static constexpr const char *kAttributeCountLimitEnv = "OTEL_ATTRIBUTE_COUNT_LIMIT";
static constexpr const char *kSpanAttributeValueLengthLimitEnv =
"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT";
static constexpr const char *kSpanAttributeCountLimitEnv = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT";
static constexpr const char *kSpanEventCountLimitEnv = "OTEL_SPAN_EVENT_COUNT_LIMIT";
static constexpr const char *kSpanLinkCountLimitEnv = "OTEL_SPAN_LINK_COUNT_LIMIT";
static constexpr const char *kEventAttributeCountLimitEnv = "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT";
static constexpr const char *kLinkAttributeCountLimitEnv = "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT";

namespace
{

void UpdateFromEnv(const char *env_var_name, std::uint32_t &limit)
{
std::uint32_t value{};
if (opentelemetry::sdk::common::GetUintEnvironmentVariable(env_var_name, value))
{
limit = value;
}
}

void UpdateFromEnv(const char *env_var_name, std::size_t &limit)
{
std::uint32_t value{};
if (opentelemetry::sdk::common::GetUintEnvironmentVariable(env_var_name, value))
{
limit = static_cast<std::size_t>(value);
}
}

} // namespace

SpanLimits GetSpanLimitsFromEnv()
{
SpanLimits limits = SpanLimits::NoLimits();

// General attribute limits first; the span-specific variables below take precedence.
UpdateFromEnv(kAttributeValueLengthLimitEnv, limits.attribute_value_length_limit);
UpdateFromEnv(kAttributeCountLimitEnv, limits.attribute_count_limit);

UpdateFromEnv(kSpanAttributeValueLengthLimitEnv, limits.attribute_value_length_limit);
UpdateFromEnv(kSpanAttributeCountLimitEnv, limits.attribute_count_limit);
UpdateFromEnv(kSpanEventCountLimitEnv, limits.event_count_limit);
UpdateFromEnv(kSpanLinkCountLimitEnv, limits.link_count_limit);
UpdateFromEnv(kEventAttributeCountLimitEnv, limits.event_attribute_count_limit);
UpdateFromEnv(kLinkAttributeCountLimitEnv, limits.link_attribute_count_limit);

return limits;
}

} // namespace span_limits_env
} // namespace trace
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
4 changes: 2 additions & 2 deletions sdk/src/trace/tracer_provider_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory
std::unique_ptr<instrumentationscope::ScopeConfigurator<TracerConfig>> tracer_configurator)
{
return Create(std::move(processor), resource, std::move(sampler), std::move(id_generator),
std::move(tracer_configurator), SpanLimits::NoLimits());
std::move(tracer_configurator), span_limits_env::GetSpanLimitsFromEnv());
}

std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory::Create(
Expand Down Expand Up @@ -135,7 +135,7 @@ std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory
std::unique_ptr<instrumentationscope::ScopeConfigurator<TracerConfig>> tracer_configurator)
{
return Create(std::move(processors), resource, std::move(sampler), std::move(id_generator),
std::move(tracer_configurator), SpanLimits::NoLimits());
std::move(tracer_configurator), span_limits_env::GetSpanLimitsFromEnv());
}

std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory::Create(
Expand Down
103 changes: 103 additions & 0 deletions sdk/test/trace/tracer_provider_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

#include <gtest/gtest.h>
#include <stdlib.h>
#include <atomic>
#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -37,6 +38,12 @@
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/tracer.h"

#if defined(_MSC_VER)
# include "opentelemetry/sdk/common/env_variables.h"
using opentelemetry::sdk::common::setenv;
using opentelemetry::sdk::common::unsetenv;
#endif

#if OPENTELEMETRY_ABI_VERSION_NO >= 2
# include <initializer_list>
# include <map>
Expand Down Expand Up @@ -569,6 +576,102 @@ TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreate)
EXPECT_EQ(stored.link_attribute_count_limit, limits.link_attribute_count_limit);
}

namespace
{

void UnsetSpanLimitsEnv()
{
unsetenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT");
unsetenv("OTEL_ATTRIBUTE_COUNT_LIMIT");
unsetenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT");
unsetenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT");
unsetenv("OTEL_SPAN_EVENT_COUNT_LIMIT");
unsetenv("OTEL_SPAN_LINK_COUNT_LIMIT");
unsetenv("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT");
unsetenv("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT");
}

} // namespace

TEST(TracerProvider, SpanLimitsFromEnvUnsetIsNoLimits)
{
UnsetSpanLimitsEnv();

const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
const SpanLimits no_limits = SpanLimits::NoLimits();
EXPECT_EQ(limits.attribute_count_limit, no_limits.attribute_count_limit);
EXPECT_EQ(limits.attribute_value_length_limit, no_limits.attribute_value_length_limit);
EXPECT_EQ(limits.event_count_limit, no_limits.event_count_limit);
EXPECT_EQ(limits.link_count_limit, no_limits.link_count_limit);
EXPECT_EQ(limits.event_attribute_count_limit, no_limits.event_attribute_count_limit);
EXPECT_EQ(limits.link_attribute_count_limit, no_limits.link_attribute_count_limit);
}

TEST(TracerProvider, SpanLimitsFromEnvReadsVariables)
{
UnsetSpanLimitsEnv();
setenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "100", 1);
setenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "5", 1);
setenv("OTEL_SPAN_EVENT_COUNT_LIMIT", "3", 1);
setenv("OTEL_SPAN_LINK_COUNT_LIMIT", "2", 1);
setenv("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", "4", 1);
setenv("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", "6", 1);

const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
EXPECT_EQ(limits.attribute_value_length_limit, 100u);
EXPECT_EQ(limits.attribute_count_limit, 5u);
EXPECT_EQ(limits.event_count_limit, 3u);
EXPECT_EQ(limits.link_count_limit, 2u);
EXPECT_EQ(limits.event_attribute_count_limit, 4u);
EXPECT_EQ(limits.link_attribute_count_limit, 6u);

UnsetSpanLimitsEnv();
}

TEST(TracerProvider, SpanLimitsFromEnvGeneralAttributeVariablesApply)
{
UnsetSpanLimitsEnv();
setenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "50", 1);
setenv("OTEL_ATTRIBUTE_COUNT_LIMIT", "10", 1);

const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
EXPECT_EQ(limits.attribute_value_length_limit, 50u);
EXPECT_EQ(limits.attribute_count_limit, 10u);
EXPECT_EQ(limits.event_count_limit, (std::numeric_limits<std::uint32_t>::max)());

UnsetSpanLimitsEnv();
}

TEST(TracerProvider, SpanLimitsFromEnvSpanSpecificTakesPrecedence)
{
UnsetSpanLimitsEnv();
setenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "50", 1);
setenv("OTEL_ATTRIBUTE_COUNT_LIMIT", "10", 1);
setenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "100", 1);
setenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "20", 1);

const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
EXPECT_EQ(limits.attribute_value_length_limit, 100u);
EXPECT_EQ(limits.attribute_count_limit, 20u);

UnsetSpanLimitsEnv();
}

TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreateDefaultReadsEnv)
{
UnsetSpanLimitsEnv();
setenv("OTEL_SPAN_EVENT_COUNT_LIMIT", "42", 1);

auto provider = TracerProviderFactory::Create(std::make_unique<SimpleSpanProcessor>(nullptr));

const auto &limits = provider->GetSpanLimits();
EXPECT_EQ(limits.event_count_limit, 42u);
EXPECT_EQ(limits.attribute_count_limit, (std::numeric_limits<std::uint32_t>::max)());
EXPECT_EQ(limits.link_count_limit, (std::numeric_limits<std::uint32_t>::max)());

UnsetSpanLimitsEnv();
}

TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreateDefault)
{
auto provider = TracerProviderFactory::Create(std::make_unique<SimpleSpanProcessor>(nullptr));
Expand Down
Loading