Skip to content

Commit 1f21f0b

Browse files
HrMathematikerDmitrii Korzhimanov
authored andcommitted
[SDK] Read span limits from environment variables
Adds span_limits_env::GetSpanLimitsFromEnv(), which builds a SpanLimits from the environment variables defined in the specification (OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT, OTEL_SPAN_LINK_COUNT_LIMIT, OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT, OTEL_LINK_ATTRIBUTE_COUNT_LIMIT, and the general OTEL_ATTRIBUTE_* fallbacks), and uses it as the default in the TracerProviderFactory::Create overloads that previously defaulted to SpanLimits::NoLimits(). A field whose variable is unset keeps its NoLimits() value, so behavior is unchanged when no variables are set; explicitly passed SpanLimits keep taking precedence.
1 parent 0e2406e commit 1f21f0b

6 files changed

Lines changed: 205 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ Increment the:
1515

1616
## [Unreleased]
1717

18+
* [SDK] Read span limits from the environment variables defined in the
19+
specification (OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT,
20+
OTEL_SPAN_LINK_COUNT_LIMIT, ...) in the TracerProviderFactory overloads
21+
that do not receive explicit SpanLimits
22+
[#4258](https://github.com/open-telemetry/opentelemetry-cpp/pull/4258)
23+
1824
* docs: update supported development platforms
1925
[#4260](https://github.com/open-telemetry/opentelemetry-cpp/pull/4260)
2026

sdk/include/opentelemetry/sdk/trace/span_limits.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,24 @@ struct SpanLimits
6363
}
6464
};
6565

66+
namespace span_limits_env
67+
{
68+
69+
/**
70+
* @brief Returns span limits read from the environment variables defined in the
71+
* OpenTelemetry specification
72+
* (https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits).
73+
*
74+
* A field whose environment variable is not set keeps its SpanLimits::NoLimits() value, so with
75+
* no variables set the result equals SpanLimits::NoLimits() and SDK behavior is unchanged. The
76+
* span-specific variables (OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
77+
* OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT) take precedence over the general ones
78+
* (OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, OTEL_ATTRIBUTE_COUNT_LIMIT).
79+
*/
80+
OPENTELEMETRY_EXPORT SpanLimits GetSpanLimitsFromEnv();
81+
82+
} // namespace span_limits_env
83+
6684
} // namespace trace
6785
} // namespace sdk
6886
OPENTELEMETRY_END_NAMESPACE

sdk/src/trace/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_library(
1616
batch_span_processor_options.cc
1717
simple_processor_factory.cc
1818
span_data.cc
19+
span_limits.cc
1920
samplers/always_on_factory.cc
2021
samplers/always_off_factory.cc
2122
samplers/parent.cc

sdk/src/trace/span_limits.cc

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include <cstddef>
5+
#include <cstdint>
6+
7+
#include "opentelemetry/sdk/common/env_variables.h"
8+
#include "opentelemetry/sdk/trace/span_limits.h"
9+
#include "opentelemetry/version.h"
10+
11+
OPENTELEMETRY_BEGIN_NAMESPACE
12+
namespace sdk
13+
{
14+
namespace trace
15+
{
16+
namespace span_limits_env
17+
{
18+
19+
// Environment variable names, see
20+
// https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits
21+
static constexpr const char *kAttributeValueLengthLimitEnv = "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT";
22+
static constexpr const char *kAttributeCountLimitEnv = "OTEL_ATTRIBUTE_COUNT_LIMIT";
23+
static constexpr const char *kSpanAttributeValueLengthLimitEnv =
24+
"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT";
25+
static constexpr const char *kSpanAttributeCountLimitEnv = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT";
26+
static constexpr const char *kSpanEventCountLimitEnv = "OTEL_SPAN_EVENT_COUNT_LIMIT";
27+
static constexpr const char *kSpanLinkCountLimitEnv = "OTEL_SPAN_LINK_COUNT_LIMIT";
28+
static constexpr const char *kEventAttributeCountLimitEnv = "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT";
29+
static constexpr const char *kLinkAttributeCountLimitEnv = "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT";
30+
31+
namespace
32+
{
33+
34+
void UpdateFromEnv(const char *env_var_name, std::uint32_t &limit)
35+
{
36+
std::uint32_t value{};
37+
if (opentelemetry::sdk::common::GetUintEnvironmentVariable(env_var_name, value))
38+
{
39+
limit = value;
40+
}
41+
}
42+
43+
void UpdateFromEnv(const char *env_var_name, std::size_t &limit)
44+
{
45+
std::uint32_t value{};
46+
if (opentelemetry::sdk::common::GetUintEnvironmentVariable(env_var_name, value))
47+
{
48+
limit = static_cast<std::size_t>(value);
49+
}
50+
}
51+
52+
} // namespace
53+
54+
SpanLimits GetSpanLimitsFromEnv()
55+
{
56+
SpanLimits limits = SpanLimits::NoLimits();
57+
58+
// General attribute limits first; the span-specific variables below take precedence.
59+
UpdateFromEnv(kAttributeValueLengthLimitEnv, limits.attribute_value_length_limit);
60+
UpdateFromEnv(kAttributeCountLimitEnv, limits.attribute_count_limit);
61+
62+
UpdateFromEnv(kSpanAttributeValueLengthLimitEnv, limits.attribute_value_length_limit);
63+
UpdateFromEnv(kSpanAttributeCountLimitEnv, limits.attribute_count_limit);
64+
UpdateFromEnv(kSpanEventCountLimitEnv, limits.event_count_limit);
65+
UpdateFromEnv(kSpanLinkCountLimitEnv, limits.link_count_limit);
66+
UpdateFromEnv(kEventAttributeCountLimitEnv, limits.event_attribute_count_limit);
67+
UpdateFromEnv(kLinkAttributeCountLimitEnv, limits.link_attribute_count_limit);
68+
69+
return limits;
70+
}
71+
72+
} // namespace span_limits_env
73+
} // namespace trace
74+
} // namespace sdk
75+
OPENTELEMETRY_END_NAMESPACE

sdk/src/trace/tracer_provider_factory.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory
7171
std::unique_ptr<instrumentationscope::ScopeConfigurator<TracerConfig>> tracer_configurator)
7272
{
7373
return Create(std::move(processor), resource, std::move(sampler), std::move(id_generator),
74-
std::move(tracer_configurator), SpanLimits::NoLimits());
74+
std::move(tracer_configurator), span_limits_env::GetSpanLimitsFromEnv());
7575
}
7676

7777
std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory::Create(
@@ -135,7 +135,7 @@ std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory
135135
std::unique_ptr<instrumentationscope::ScopeConfigurator<TracerConfig>> tracer_configurator)
136136
{
137137
return Create(std::move(processors), resource, std::move(sampler), std::move(id_generator),
138-
std::move(tracer_configurator), SpanLimits::NoLimits());
138+
std::move(tracer_configurator), span_limits_env::GetSpanLimitsFromEnv());
139139
}
140140

141141
std::unique_ptr<opentelemetry::sdk::trace::TracerProvider> TracerProviderFactory::Create(

sdk/test/trace/tracer_provider_test.cc

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
#include <gtest/gtest.h>
5+
#include <stdlib.h>
56
#include <atomic>
67
#include <cstddef>
78
#include <cstdint>
@@ -37,6 +38,12 @@
3738
#include "opentelemetry/trace/span.h"
3839
#include "opentelemetry/trace/tracer.h"
3940

41+
#if defined(_MSC_VER)
42+
# include "opentelemetry/sdk/common/env_variables.h"
43+
using opentelemetry::sdk::common::setenv;
44+
using opentelemetry::sdk::common::unsetenv;
45+
#endif
46+
4047
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
4148
# include <initializer_list>
4249
# include <map>
@@ -569,6 +576,102 @@ TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreate)
569576
EXPECT_EQ(stored.link_attribute_count_limit, limits.link_attribute_count_limit);
570577
}
571578

579+
namespace
580+
{
581+
582+
void UnsetSpanLimitsEnv()
583+
{
584+
unsetenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT");
585+
unsetenv("OTEL_ATTRIBUTE_COUNT_LIMIT");
586+
unsetenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT");
587+
unsetenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT");
588+
unsetenv("OTEL_SPAN_EVENT_COUNT_LIMIT");
589+
unsetenv("OTEL_SPAN_LINK_COUNT_LIMIT");
590+
unsetenv("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT");
591+
unsetenv("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT");
592+
}
593+
594+
} // namespace
595+
596+
TEST(TracerProvider, SpanLimitsFromEnvUnsetIsNoLimits)
597+
{
598+
UnsetSpanLimitsEnv();
599+
600+
const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
601+
const SpanLimits no_limits = SpanLimits::NoLimits();
602+
EXPECT_EQ(limits.attribute_count_limit, no_limits.attribute_count_limit);
603+
EXPECT_EQ(limits.attribute_value_length_limit, no_limits.attribute_value_length_limit);
604+
EXPECT_EQ(limits.event_count_limit, no_limits.event_count_limit);
605+
EXPECT_EQ(limits.link_count_limit, no_limits.link_count_limit);
606+
EXPECT_EQ(limits.event_attribute_count_limit, no_limits.event_attribute_count_limit);
607+
EXPECT_EQ(limits.link_attribute_count_limit, no_limits.link_attribute_count_limit);
608+
}
609+
610+
TEST(TracerProvider, SpanLimitsFromEnvReadsVariables)
611+
{
612+
UnsetSpanLimitsEnv();
613+
setenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "100", 1);
614+
setenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "5", 1);
615+
setenv("OTEL_SPAN_EVENT_COUNT_LIMIT", "3", 1);
616+
setenv("OTEL_SPAN_LINK_COUNT_LIMIT", "2", 1);
617+
setenv("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", "4", 1);
618+
setenv("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", "6", 1);
619+
620+
const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
621+
EXPECT_EQ(limits.attribute_value_length_limit, 100u);
622+
EXPECT_EQ(limits.attribute_count_limit, 5u);
623+
EXPECT_EQ(limits.event_count_limit, 3u);
624+
EXPECT_EQ(limits.link_count_limit, 2u);
625+
EXPECT_EQ(limits.event_attribute_count_limit, 4u);
626+
EXPECT_EQ(limits.link_attribute_count_limit, 6u);
627+
628+
UnsetSpanLimitsEnv();
629+
}
630+
631+
TEST(TracerProvider, SpanLimitsFromEnvGeneralAttributeVariablesApply)
632+
{
633+
UnsetSpanLimitsEnv();
634+
setenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "50", 1);
635+
setenv("OTEL_ATTRIBUTE_COUNT_LIMIT", "10", 1);
636+
637+
const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
638+
EXPECT_EQ(limits.attribute_value_length_limit, 50u);
639+
EXPECT_EQ(limits.attribute_count_limit, 10u);
640+
EXPECT_EQ(limits.event_count_limit, (std::numeric_limits<std::uint32_t>::max)());
641+
642+
UnsetSpanLimitsEnv();
643+
}
644+
645+
TEST(TracerProvider, SpanLimitsFromEnvSpanSpecificTakesPrecedence)
646+
{
647+
UnsetSpanLimitsEnv();
648+
setenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "50", 1);
649+
setenv("OTEL_ATTRIBUTE_COUNT_LIMIT", "10", 1);
650+
setenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "100", 1);
651+
setenv("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "20", 1);
652+
653+
const SpanLimits limits = span_limits_env::GetSpanLimitsFromEnv();
654+
EXPECT_EQ(limits.attribute_value_length_limit, 100u);
655+
EXPECT_EQ(limits.attribute_count_limit, 20u);
656+
657+
UnsetSpanLimitsEnv();
658+
}
659+
660+
TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreateDefaultReadsEnv)
661+
{
662+
UnsetSpanLimitsEnv();
663+
setenv("OTEL_SPAN_EVENT_COUNT_LIMIT", "42", 1);
664+
665+
auto provider = TracerProviderFactory::Create(std::make_unique<SimpleSpanProcessor>(nullptr));
666+
667+
const auto &limits = provider->GetSpanLimits();
668+
EXPECT_EQ(limits.event_count_limit, 42u);
669+
EXPECT_EQ(limits.attribute_count_limit, (std::numeric_limits<std::uint32_t>::max)());
670+
EXPECT_EQ(limits.link_count_limit, (std::numeric_limits<std::uint32_t>::max)());
671+
672+
UnsetSpanLimitsEnv();
673+
}
674+
572675
TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreateDefault)
573676
{
574677
auto provider = TracerProviderFactory::Create(std::make_unique<SimpleSpanProcessor>(nullptr));

0 commit comments

Comments
 (0)