2 * Copyright (c) 2017 Uber Technologies, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <gtest/gtest.h>
21 #include "jaegertracing/Constants.h"
22 #include "jaegertracing/Tag.h"
23 #include "jaegertracing/samplers/AdaptiveSampler.h"
24 #include "jaegertracing/samplers/Config.h"
25 #include "jaegertracing/samplers/ConstSampler.h"
26 #include "jaegertracing/samplers/GuaranteedThroughputProbabilisticSampler.h"
27 #include "jaegertracing/samplers/ProbabilisticSampler.h"
28 #include "jaegertracing/samplers/RateLimitingSampler.h"
29 #include "jaegertracing/samplers/RemotelyControlledSampler.h"
30 #include "jaegertracing/samplers/Sampler.h"
31 #include "jaegertracing/samplers/SamplingStatus.h"
32 #include "jaegertracing/testutils/MockAgent.h"
33 #include "jaegertracing/testutils/TUDPTransport.h"
34 #include "jaegertracing/thrift-gen/jaeger_types.h"
36 namespace jaegertracing
{
40 constexpr auto kTestOperationName
= "op";
41 constexpr auto kTestFirstTimeOperationName
= "firstTimeOp";
42 constexpr auto kTestDefaultSamplingProbability
= 0.5;
43 constexpr auto kTestMaxID
= std::numeric_limits
<uint64_t>::max() / 2 + 1;
44 constexpr auto kTestDefaultMaxOperations
= 10;
46 const Tag testProbablisticExpectedTags
[] = {
47 { "sampler.type", "probabilistic" }, { "sampler.param", 0.5 }
50 const Tag testLowerBoundExpectedTags
[] = { { "sampler.type", "lowerbound" },
51 { "sampler.param", 0.5 } };
53 #define CMP_TAGS(tagArr, tagVec) \
55 ASSERT_EQ(sizeof(tagArr) / sizeof(Tag), (tagVec).size()); \
56 for (auto i = static_cast<size_t>(0); i < (tagVec).size(); ++i) { \
57 jaegertracing::thrift::Tag thriftTagArr; \
58 jaegertracing::thrift::Tag thriftTagVec; \
59 (tagArr)[i].thrift(thriftTagArr); \
60 (tagVec)[i].thrift(thriftTagVec); \
61 ASSERT_EQ(thriftTagArr, thriftTagVec); \
65 } // anonymous namespace
67 TEST(Sampler
, testSamplerTags
)
69 ConstSampler
constTrue(true);
70 ConstSampler
constFalse(false);
71 ProbabilisticSampler
prob(0.1);
72 RateLimitingSampler
rate(0.1);
76 std::string _samplerType
;
77 Tag::ValueType _samplerParam
;
78 } tests
[] = { { constTrue
, "const", true },
79 { constFalse
, "const", false },
80 { prob
, "probabilistic", 0.1 },
81 { rate
, "ratelimiting", 0.1 } };
83 for (auto&& test
: tests
) {
85 test
._sampler
.isSampled(TraceID(), kTestOperationName
).tags();
87 for (auto&& tag
: tags
) {
88 if (tag
.key() == kSamplerTypeTagKey
) {
89 ASSERT_TRUE(tag
.value().is
<const char*>());
90 ASSERT_EQ(test
._samplerType
, tag
.value().get
<const char*>());
93 else if (tag
.key() == kSamplerParamTagKey
) {
94 ASSERT_EQ(test
._samplerParam
, tag
.value());
102 TEST(Sampler
, testProbabilisticSamplerErrors
)
104 ProbabilisticSampler
sampler(-0.1);
105 ASSERT_LE(0, sampler
.samplingRate());
106 ASSERT_GE(1, sampler
.samplingRate());
107 sampler
= ProbabilisticSampler(1.1);
108 ASSERT_LE(0, sampler
.samplingRate());
109 ASSERT_GE(1, sampler
.samplingRate());
112 TEST(Sampler
, testProbabilisticSampler
)
115 ProbabilisticSampler
sampler(0.5);
117 sampler
.isSampled(TraceID(0, kTestMaxID
+ 10), kTestOperationName
);
118 ASSERT_FALSE(result
.isSampled());
119 CMP_TAGS(testProbablisticExpectedTags
, result
.tags());
122 sampler
.isSampled(TraceID(0, kTestMaxID
- 20), kTestOperationName
);
123 ASSERT_TRUE(result
.isSampled());
124 CMP_TAGS(testProbablisticExpectedTags
, result
.tags());
127 ProbabilisticSampler
sampler(1.0);
129 sampler
.isSampled(TraceID(0, kTestMaxID
), kTestOperationName
);
130 ASSERT_TRUE(result
.isSampled());
133 sampler
.isSampled(TraceID(0, kTestMaxID
- 20), kTestOperationName
);
134 ASSERT_TRUE(result
.isSampled());
138 TEST(Sampler
, testProbabilisticSamplerPerformance
)
140 constexpr auto kNumSamples
= static_cast<uint64_t>(10000);
142 ProbabilisticSampler
sampler(0.001);
143 std::random_device randomDevice
;
144 std::default_random_engine
randomGenerator(randomDevice());
145 std::uniform_int_distribution
<uint64_t> distribution
;
146 auto count
= static_cast<uint64_t>(0);
147 for (auto i
= static_cast<uint64_t>(0); i
< kNumSamples
; ++i
) {
148 TraceID
id(0, distribution(randomGenerator
));
149 if (sampler
.isSampled(id
, kTestOperationName
).isSampled()) {
153 const auto rate
= static_cast<double>(count
) / kNumSamples
;
154 std::cout
<< "Sampled: " << count
<< " rate=" << rate
<< '\n';
157 TEST(Sampler
, testProbabilisticSamplerInvalidRate
)
159 Config
samplerConfig1(kSamplerTypeProbabilistic
,
163 samplers::Config::Clock::duration());
164 Config
samplerConfig2(kSamplerTypeProbabilistic
,
168 samplers::Config::Clock::duration());
169 auto logger
= logging::nullLogger();
170 auto metrics
= metrics::Metrics::makeNullMetrics();
171 ASSERT_THROW(samplerConfig1
.makeSampler("test-service", *logger
, *metrics
),
172 std::invalid_argument
);
173 ASSERT_THROW(samplerConfig2
.makeSampler("test-service", *logger
, *metrics
),
174 std::invalid_argument
);
177 TEST(Sampler
, testRateLimitingSampler
)
180 RateLimitingSampler
sampler(2);
181 auto result
= sampler
.isSampled(TraceID(), kTestOperationName
);
182 ASSERT_TRUE(result
.isSampled());
183 result
= sampler
.isSampled(TraceID(), kTestOperationName
);
184 ASSERT_TRUE(result
.isSampled());
185 result
= sampler
.isSampled(TraceID(), kTestOperationName
);
186 ASSERT_FALSE(result
.isSampled());
190 RateLimitingSampler
sampler(0.1);
191 auto result
= sampler
.isSampled(TraceID(), kTestOperationName
);
192 ASSERT_TRUE(result
.isSampled());
193 result
= sampler
.isSampled(TraceID(), kTestOperationName
);
194 ASSERT_FALSE(result
.isSampled());
198 TEST(Sampler
, testGuaranteedThroughputProbabilisticSamplerUpdate
)
200 auto lowerBound
= 2.0;
201 auto samplingRate
= 0.5;
202 GuaranteedThroughputProbabilisticSampler
sampler(lowerBound
, samplingRate
);
203 ASSERT_EQ(lowerBound
, sampler
.lowerBound());
204 ASSERT_EQ(samplingRate
, sampler
.samplingRate());
206 auto newLowerBound
= 1.0;
207 auto newSamplingRate
= 0.6;
208 sampler
.update(newLowerBound
, newSamplingRate
);
209 ASSERT_EQ(newLowerBound
, sampler
.lowerBound());
210 ASSERT_EQ(newSamplingRate
, sampler
.samplingRate());
212 newSamplingRate
= 1.1;
213 sampler
.update(newLowerBound
, newSamplingRate
);
214 ASSERT_EQ(1.0, sampler
.samplingRate());
217 TEST(Sampler
, testAdaptiveSampler
)
219 namespace thriftgen
= sampling_manager::thrift
;
221 thriftgen::OperationSamplingStrategy strategy
;
222 strategy
.__set_operation(kTestOperationName
);
223 thriftgen::ProbabilisticSamplingStrategy probabilisticSampling
;
224 probabilisticSampling
.__set_samplingRate(kTestDefaultSamplingProbability
);
225 strategy
.__set_probabilisticSampling(probabilisticSampling
);
227 thriftgen::PerOperationSamplingStrategies strategies
;
228 strategies
.__set_defaultSamplingProbability(
229 kTestDefaultSamplingProbability
);
230 strategies
.__set_defaultLowerBoundTracesPerSecond(1.0);
231 strategies
.__set_perOperationStrategies({ strategy
});
233 AdaptiveSampler
sampler(strategies
, kTestDefaultMaxOperations
);
235 sampler
.isSampled(TraceID(0, kTestMaxID
+ 10), kTestOperationName
);
236 ASSERT_TRUE(result
.isSampled());
237 CMP_TAGS(testLowerBoundExpectedTags
, result
.tags());
239 result
= sampler
.isSampled(TraceID(0, kTestMaxID
- 20), kTestOperationName
);
240 ASSERT_TRUE(result
.isSampled());
241 CMP_TAGS(testProbablisticExpectedTags
, result
.tags());
243 result
= sampler
.isSampled(TraceID(0, kTestMaxID
+ 10), kTestOperationName
);
244 ASSERT_FALSE(result
.isSampled());
246 result
= sampler
.isSampled(TraceID(0, kTestMaxID
- 20),
247 kTestFirstTimeOperationName
);
248 ASSERT_TRUE(result
.isSampled());
249 CMP_TAGS(testProbablisticExpectedTags
, result
.tags());
252 TEST(Sampler
, testAdaptiveSamplerErrors
)
254 namespace thriftgen
= sampling_manager::thrift
;
256 thriftgen::OperationSamplingStrategy strategy
;
257 strategy
.__set_operation(kTestOperationName
);
258 thriftgen::ProbabilisticSamplingStrategy probabilisticSampling
;
259 probabilisticSampling
.__set_samplingRate(-0.1);
260 strategy
.__set_probabilisticSampling(probabilisticSampling
);
262 thriftgen::PerOperationSamplingStrategies strategies
;
263 strategies
.__set_defaultSamplingProbability(
264 kTestDefaultSamplingProbability
);
265 strategies
.__set_defaultLowerBoundTracesPerSecond(2.0);
266 strategies
.__set_perOperationStrategies({ strategy
});
269 AdaptiveSampler
sampler(strategies
, kTestDefaultMaxOperations
);
273 strategies
.perOperationStrategies
.at(0)
274 .probabilisticSampling
.__set_samplingRate(1.1);
275 AdaptiveSampler
sampler(strategies
, kTestDefaultMaxOperations
);
279 TEST(Sampler
, testAdaptiveSamplerUpdate
)
281 namespace thriftgen
= sampling_manager::thrift
;
283 constexpr auto kSamplingRate
= 0.1;
284 constexpr auto kLowerBound
= 2.0;
286 thriftgen::OperationSamplingStrategy strategy
;
287 strategy
.__set_operation(kTestOperationName
);
288 thriftgen::ProbabilisticSamplingStrategy probabilisticSampling
;
289 probabilisticSampling
.__set_samplingRate(kSamplingRate
);
290 strategy
.__set_probabilisticSampling(probabilisticSampling
);
292 thriftgen::PerOperationSamplingStrategies strategies
;
293 strategies
.__set_defaultSamplingProbability(
294 kTestDefaultSamplingProbability
);
295 strategies
.__set_defaultLowerBoundTracesPerSecond(kLowerBound
);
296 strategies
.__set_perOperationStrategies({ strategy
});
298 AdaptiveSampler
sampler(strategies
, kTestDefaultMaxOperations
);
300 constexpr auto kNewSamplingRate
= 0.2;
301 constexpr auto kNewLowerBound
= 3.0;
302 constexpr auto kNewDefaultSamplingProbability
= 0.1;
304 // Updated kTestOperationName strategy.
305 thriftgen::OperationSamplingStrategy updatedStrategy
;
306 updatedStrategy
.__set_operation(kTestOperationName
);
307 thriftgen::ProbabilisticSamplingStrategy updatedProbabilisticSampling
;
308 updatedProbabilisticSampling
.__set_samplingRate(kNewSamplingRate
);
309 updatedStrategy
.__set_probabilisticSampling(updatedProbabilisticSampling
);
311 // New kTestFirstTimeOperationName strategy.
312 thriftgen::OperationSamplingStrategy newStrategy
;
313 newStrategy
.__set_operation(kTestFirstTimeOperationName
);
314 thriftgen::ProbabilisticSamplingStrategy newProbabilisticSampling
;
315 newProbabilisticSampling
.__set_samplingRate(kNewSamplingRate
);
316 newStrategy
.__set_probabilisticSampling(newProbabilisticSampling
);
318 thriftgen::PerOperationSamplingStrategies newStrategies
;
319 newStrategies
.__set_defaultSamplingProbability(
320 kNewDefaultSamplingProbability
);
321 newStrategies
.__set_defaultLowerBoundTracesPerSecond(kNewLowerBound
);
322 newStrategies
.__set_perOperationStrategies(
323 { updatedStrategy
, newStrategy
});
325 sampler
.update(newStrategies
);
328 TEST(Sampler
, testRemotelyControlledSampler
)
330 const auto mockAgent
= testutils::MockAgent::make();
332 const auto logger
= logging::nullLogger();
333 const auto metrics
= metrics::Metrics::makeNullMetrics();
335 // Make sure remote sampling probability is 1
336 sampling_manager::thrift::SamplingStrategyResponse config
;
337 config
.__set_strategyType(
338 sampling_manager::thrift::SamplingStrategyType::PROBABILISTIC
);
339 sampling_manager::thrift::ProbabilisticSamplingStrategy probaStrategy
;
340 probaStrategy
.__set_samplingRate(1.0);
341 config
.__set_probabilisticSampling(probaStrategy
);
342 mockAgent
->addSamplingStrategy("test-service", config
);
344 // Default probability of 0.5, switches to 1 when downloaded
345 RemotelyControlledSampler
sampler(
347 "http://" + mockAgent
->samplingServerAddress().authority(),
348 std::make_shared
<ProbabilisticSampler
>(kTestDefaultSamplingProbability
),
349 kTestDefaultMaxOperations
,
350 std::chrono::milliseconds(100),
354 // Wait a bit for remote config download to be done
355 std::this_thread::sleep_for(std::chrono::milliseconds(100));
356 std::random_device device
;
359 for (auto startTime
= RemotelyControlledSampler::Clock::now();
360 std::chrono::duration_cast
<std::chrono::seconds
>(
361 RemotelyControlledSampler::Clock::now() - startTime
)
363 TraceID
traceID(rng(), rng());
364 // If probability was 0.5 we could reasonnably assume one of 50 samples fail
365 ASSERT_TRUE(sampler
.isSampled(traceID
, kTestOperationName
).isSampled());
366 std::this_thread::sleep_for(std::chrono::milliseconds(20));
371 } // namespace samplers
372 } // namespace jaegertracing