Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace OpenTelemetry {
namespace {

constexpr std::chrono::minutes SAMPLING_UPDATE_TIMER_DURATION{1};
const char* SAMPLING_EXTRAPOLATION_SPAN_ATTRIBUTE_NAME = "sampling_extrapolation_set_in_sampler";

class DynatraceTag {
public:
Expand Down Expand Up @@ -73,6 +72,26 @@ class DynatraceTag {
uint32_t path_info_;
};

// add Dynatrace specific span attributes
void addSamplingAttributes(uint32_t sampling_exponent,
std::map<std::string, std::string>& attributes) {

const auto multiplicity = SamplingState::toMultiplicity(sampling_exponent);
// The denominator of the sampling ratio. If, for example, the Dynatrace OneAgent samples with a
// probability of 1/16, the value of supportability.atm_sampling_ratio would be 16.
// Note: Ratio is also known as multiplicity.
attributes["supportability.atm_sampling_ratio"] = std::to_string(multiplicity);

if (multiplicity > 1) {
static constexpr uint64_t two_pow_56 = 1lu << 56; // 2^56
// The sampling probability can be interpreted as the number of spans
// that are discarded out of 2^56. The attribute is only available if the sampling.threshold is
// not 0 and therefore sampling happened.
const uint64_t sampling_threshold = two_pow_56 - two_pow_56 / multiplicity;
attributes["sampling.threshold"] = std::to_string(sampling_threshold);
}
}

} // namespace

DynatraceSampler::DynatraceSampler(
Expand Down Expand Up @@ -118,9 +137,7 @@ SamplingResult DynatraceSampler::shouldSample(const absl::optional<SpanContext>
if (DynatraceTag dynatrace_tag = DynatraceTag::create(trace_state_value);
dynatrace_tag.isValid()) {
result.decision = dynatrace_tag.isIgnored() ? Decision::Drop : Decision::RecordAndSample;
// TODO: change attribute name and value in scope of OA-26680
att[SAMPLING_EXTRAPOLATION_SPAN_ATTRIBUTE_NAME] =
std::to_string(dynatrace_tag.getSamplingExponent());
addSamplingAttributes(dynatrace_tag.getSamplingExponent(), att);
result.tracestate = parent_context->tracestate();
}
} else {
Expand All @@ -130,8 +147,8 @@ SamplingResult DynatraceSampler::shouldSample(const absl::optional<SpanContext>
const auto sampling_state = sampling_controller_.getSamplingState(sampling_key);
const bool sample = sampling_state.shouldSample(hash);
const auto sampling_exponent = sampling_state.getExponent();
// TODO: change attribute name and value in scope of OA-26680
att[SAMPLING_EXTRAPOLATION_SPAN_ATTRIBUTE_NAME] = std::to_string(sampling_exponent);

addSamplingAttributes(sampling_exponent, att);

result.decision = sample ? Decision::RecordAndSample : Decision::Drop;
// create new forward tag and add it to tracestate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ TEST_F(DynatraceSamplerTest, TestWithoutParentContext) {
::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {});
EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample);
EXPECT_EQ(sampling_result.attributes->size(), 1);
EXPECT_STREQ(
sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1");
EXPECT_STREQ(sampling_result.tracestate.c_str(), "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95");
EXPECT_TRUE(sampling_result.isRecording());
EXPECT_TRUE(sampling_result.isSampled());
Expand All @@ -94,6 +96,8 @@ TEST_F(DynatraceSamplerTest, TestWithUnknownParentContext) {
::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {});
EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample);
EXPECT_EQ(sampling_result.attributes->size(), 1);
EXPECT_STREQ(
sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1");
// Dynatrace tracesate should be prepended
EXPECT_STREQ(sampling_result.tracestate.c_str(),
"5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,some_vendor=some_value");
Expand All @@ -110,6 +114,8 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextSampled) {
::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {});
EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample);
EXPECT_EQ(sampling_result.attributes->size(), 1);
EXPECT_STREQ(
sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1");
// tracestate should be forwarded
EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_sampled);
// sampling decision from parent should be respected
Expand All @@ -126,6 +132,11 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextIgnored) {
::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {});
EXPECT_EQ(sampling_result.decision, Decision::Drop);
EXPECT_EQ(sampling_result.attributes->size(), 1);
EXPECT_EQ(sampling_result.attributes->size(), 2);
EXPECT_STREQ(
sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "4");
EXPECT_STREQ(sampling_result.attributes->find("sampling.threshold")->second.c_str(),
"54043195528445952");
// tracestate should be forwarded
EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_ignored);
// sampling decision from parent should be respected
Expand All @@ -144,6 +155,8 @@ TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextFromDifferentTenant)
// sampling decision on tracestate should be ignored because it is from a different tenant.
EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample);
EXPECT_EQ(sampling_result.attributes->size(), 1);
EXPECT_STREQ(
sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1");
// new Dynatrace tag should be prepended, already existing tag should be kept
const char* exptected =
"5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,6666ad40-980df25c@dt=fw4;4;4af38366;0;0;1;2;123;"
Expand Down