Skip to content

Commit d655d2f

Browse files
joaopgrassiCopilot
andauthored
dynatracesampler: refactor DynatraceTag code into own file (#41823)
Commit Message: Extracts DynatraceTag class into its own file in preparation for upcoming features. Additional Description: Risk Level: Low Testing: Unit tests Docs Changes: N/A Release Notes: N/A Platform Specific Features: N/A [Optional Runtime guard:] [Optional Fixes #Issue] [Optional Fixes commit #PR or SHA] [Optional Deprecated:] [Optional [API Considerations](https://github.com/envoyproxy/envoy/blob/main/api/review_checklist.md):] --------- Signed-off-by: Joao Grassi <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent e251966 commit d655d2f

File tree

5 files changed

+141
-64
lines changed

5 files changed

+141
-64
lines changed

source/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ envoy_cc_library(
3131
],
3232
hdrs = [
3333
"dynatrace_sampler.h",
34+
"dynatrace_tag.h",
3435
"sampler_config.h",
3536
"sampler_config_provider.h",
3637
"sampling_controller.h",

source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.cc

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h"
22

33
#include <memory>
4-
#include <sstream>
54
#include <string>
65

76
#include "source/common/common/hash.h"
8-
#include "source/common/config/datasource.h"
7+
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_tag.h"
98
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h"
109
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"
1110
#include "source/extensions/tracers/opentelemetry/span_context.h"
@@ -22,68 +21,6 @@ namespace {
2221

2322
constexpr std::chrono::minutes SAMPLING_UPDATE_TIMER_DURATION{1};
2423

25-
/**
26-
* @brief Helper for creating and reading the Dynatrace tag in the tracestate http header
27-
* This tag has at least 8 values delimited by semicolon:
28-
* - tag[0]: version (currently version 4)
29-
* - tag[1] - tag[4]: unused in the sampler (always 0)
30-
* - tag[5]: ignored field. 1 if a span is ignored (not sampled), 0 otherwise
31-
* - tag[6]: sampling exponent
32-
* - tag[7]: path info
33-
*/
34-
class DynatraceTag {
35-
public:
36-
static DynatraceTag createInvalid() { return {false, false, 0, 0}; }
37-
38-
// Creates a tag using the given values.
39-
static DynatraceTag create(bool ignored, uint32_t sampling_exponent, uint32_t path_info) {
40-
return {true, ignored, sampling_exponent, path_info};
41-
}
42-
43-
// Creates a tag from a string.
44-
static DynatraceTag create(const std::string& value) {
45-
std::vector<absl::string_view> tracestate_components =
46-
absl::StrSplit(value, ';', absl::AllowEmpty());
47-
if (tracestate_components.size() < 8) {
48-
return createInvalid();
49-
}
50-
51-
if (tracestate_components[0] != "fw4") {
52-
return createInvalid();
53-
}
54-
bool ignored = tracestate_components[5] == "1";
55-
uint32_t sampling_exponent;
56-
uint32_t path_info;
57-
if (absl::SimpleAtoi(tracestate_components[6], &sampling_exponent) &&
58-
absl::SimpleHexAtoi(tracestate_components[7], &path_info)) {
59-
return {true, ignored, sampling_exponent, path_info};
60-
}
61-
return createInvalid();
62-
}
63-
64-
// Returns a Dynatrace tag as string.
65-
std::string asString() const {
66-
std::string ret = absl::StrCat("fw4;0;0;0;0;", ignored_ ? "1" : "0", ";", sampling_exponent_,
67-
";", absl::Hex(path_info_));
68-
return ret;
69-
}
70-
71-
// Returns true if parsing was successful.
72-
bool isValid() const { return valid_; };
73-
bool isIgnored() const { return ignored_; };
74-
uint32_t getSamplingExponent() const { return sampling_exponent_; };
75-
76-
private:
77-
DynatraceTag(bool valid, bool ignored, uint32_t sampling_exponent, uint32_t path_info)
78-
: valid_(valid), ignored_(ignored), sampling_exponent_(sampling_exponent),
79-
path_info_(path_info) {}
80-
81-
bool valid_;
82-
bool ignored_;
83-
uint32_t sampling_exponent_;
84-
uint32_t path_info_;
85-
};
86-
8724
// add Dynatrace specific span attributes
8825
void addSamplingAttributes(uint32_t sampling_exponent, OtelAttributes& attributes) {
8926

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
6+
#include "absl/strings/numbers.h"
7+
#include "absl/strings/str_cat.h"
8+
#include "absl/strings/str_split.h"
9+
#include "absl/strings/string_view.h"
10+
11+
namespace Envoy {
12+
namespace Extensions {
13+
namespace Tracers {
14+
namespace OpenTelemetry {
15+
16+
/**
17+
* @brief Helper for creating and reading the Dynatrace tag in the tracestate http header
18+
* This tag has at least 8 values delimited by semicolon:
19+
* - tag[0]: version (currently version 4)
20+
* - tag[1] - tag[4]: unused in the sampler (always 0)
21+
* - tag[5]: ignored field. 1 if a span is ignored (not sampled), 0 otherwise
22+
* - tag[6]: sampling exponent
23+
* - tag[7]: path info
24+
*/
25+
class DynatraceTag {
26+
public:
27+
static DynatraceTag createInvalid() { return {false, false, 0, 0}; }
28+
29+
// Creates a tag using the given values.
30+
static DynatraceTag create(bool ignored, uint32_t sampling_exponent, uint32_t path_info) {
31+
return {true, ignored, sampling_exponent, path_info};
32+
}
33+
34+
// Creates a DynatraceTag from the value in the tracestate
35+
static DynatraceTag create(const std::string& value) {
36+
std::vector<absl::string_view> tracestate_components =
37+
absl::StrSplit(value, ';', absl::AllowEmpty());
38+
if (tracestate_components.size() < 8) {
39+
return createInvalid();
40+
}
41+
42+
if (tracestate_components[0] != "fw4") {
43+
return createInvalid();
44+
}
45+
bool ignored = tracestate_components[5] == "1";
46+
uint32_t sampling_exponent;
47+
uint32_t path_info;
48+
if (absl::SimpleAtoi(tracestate_components[6], &sampling_exponent) &&
49+
absl::SimpleHexAtoi(tracestate_components[7], &path_info)) {
50+
return {true, ignored, sampling_exponent, path_info};
51+
}
52+
return createInvalid();
53+
}
54+
55+
// Returns a DynatraceTag as string.
56+
std::string asString() const {
57+
std::string ret = absl::StrCat("fw4;0;0;0;0;", ignored_ ? "1" : "0", ";", sampling_exponent_,
58+
";", absl::Hex(path_info_));
59+
return ret;
60+
}
61+
62+
// Returns true if parsing was successful.
63+
bool isValid() const { return valid_; };
64+
65+
// Returns true if the ignored flag is set.
66+
bool isIgnored() const { return ignored_; };
67+
68+
// Returns the sampling exponent.
69+
uint32_t getSamplingExponent() const { return sampling_exponent_; };
70+
71+
private:
72+
DynatraceTag(bool valid, bool ignored, uint32_t sampling_exponent, uint32_t path_info)
73+
: valid_(valid), ignored_(ignored), sampling_exponent_(sampling_exponent),
74+
path_info_(path_info) {}
75+
76+
const bool valid_;
77+
const bool ignored_;
78+
const uint32_t sampling_exponent_;
79+
const uint32_t path_info_;
80+
};
81+
82+
} // namespace OpenTelemetry
83+
} // namespace Tracers
84+
} // namespace Extensions
85+
} // namespace Envoy

test/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ envoy_extension_cc_test(
2929
name = "dynatrace_sampler_test",
3030
srcs = [
3131
"dynatrace_sampler_test.cc",
32+
"dynatrace_tag_test.cc",
3233
"sampler_config_provider_test.cc",
3334
"sampler_config_test.cc",
3435
"sampling_controller_test.cc",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_tag.h"
2+
3+
#include "gtest/gtest.h"
4+
5+
namespace Envoy {
6+
namespace Extensions {
7+
namespace Tracers {
8+
namespace OpenTelemetry {
9+
10+
class DynatraceTagTest : public ::testing::Test {};
11+
12+
TEST(DynatraceTagTest, ValidTag) {
13+
DynatraceTag new_tag = DynatraceTag::create("fw4;0;0;0;0;0;10;7b");
14+
15+
EXPECT_EQ(new_tag.isValid(), true);
16+
EXPECT_EQ(new_tag.isIgnored(), false);
17+
EXPECT_EQ(new_tag.getSamplingExponent(), 10);
18+
EXPECT_EQ(new_tag.asString(), "fw4;0;0;0;0;0;10;7b");
19+
}
20+
21+
TEST(DynatraceTagTest, IgnoredFieldSet) {
22+
DynatraceTag new_tag = DynatraceTag::create("fw4;0;0;0;0;1;10;7b");
23+
24+
EXPECT_EQ(new_tag.isValid(), true);
25+
EXPECT_EQ(new_tag.isIgnored(), true);
26+
EXPECT_EQ(new_tag.getSamplingExponent(), 10);
27+
EXPECT_EQ(new_tag.asString(), "fw4;0;0;0;0;1;10;7b");
28+
}
29+
30+
class DynatraceTagInvalidTest : public ::testing::TestWithParam<std::string> {};
31+
32+
// Verify parsing of an invalid tags
33+
TEST_P(DynatraceTagInvalidTest, InvalidTag) {
34+
DynatraceTag new_tag = DynatraceTag::create(GetParam());
35+
EXPECT_EQ(new_tag.isValid(), false);
36+
EXPECT_EQ(new_tag.asString(), "fw4;0;0;0;0;0;0;0");
37+
}
38+
39+
INSTANTIATE_TEST_SUITE_P(
40+
InvalidTagsCase, DynatraceTagInvalidTest,
41+
::testing::Values("fw4;0;0;0;0;0;10", // missing path info
42+
"fw4;0;0;0;0;0", // missing sampling exponent and path info
43+
"fw4;0;0;0;0", // missing ignored, sampling exponent and path info
44+
"fw3;0;0;0;0;0;10;7b", // invalid version
45+
"", // empty string
46+
"invalid_tag", // completely invalid string
47+
"fw400;0;0;0;10;7b" // missing delimiter between fields
48+
));
49+
50+
} // namespace OpenTelemetry
51+
} // namespace Tracers
52+
} // namespace Extensions
53+
} // namespace Envoy

0 commit comments

Comments
 (0)