]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/jaegertracing/jaeger-client-cpp/src/jaegertracing/samplers/SamplerTest.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / jaeger-client-cpp / src / jaegertracing / samplers / SamplerTest.cpp
diff --git a/ceph/src/jaegertracing/jaeger-client-cpp/src/jaegertracing/samplers/SamplerTest.cpp b/ceph/src/jaegertracing/jaeger-client-cpp/src/jaegertracing/samplers/SamplerTest.cpp
new file mode 100644 (file)
index 0000000..3c082d3
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2017 Uber Technologies, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <random>
+
+#include <gtest/gtest.h>
+
+#include "jaegertracing/Constants.h"
+#include "jaegertracing/Tag.h"
+#include "jaegertracing/samplers/AdaptiveSampler.h"
+#include "jaegertracing/samplers/Config.h"
+#include "jaegertracing/samplers/ConstSampler.h"
+#include "jaegertracing/samplers/GuaranteedThroughputProbabilisticSampler.h"
+#include "jaegertracing/samplers/ProbabilisticSampler.h"
+#include "jaegertracing/samplers/RateLimitingSampler.h"
+#include "jaegertracing/samplers/RemotelyControlledSampler.h"
+#include "jaegertracing/samplers/Sampler.h"
+#include "jaegertracing/samplers/SamplingStatus.h"
+#include "jaegertracing/testutils/MockAgent.h"
+#include "jaegertracing/testutils/TUDPTransport.h"
+#include "jaegertracing/thrift-gen/jaeger_types.h"
+
+namespace jaegertracing {
+namespace samplers {
+namespace {
+
+constexpr auto kTestOperationName = "op";
+constexpr auto kTestFirstTimeOperationName = "firstTimeOp";
+constexpr auto kTestDefaultSamplingProbability = 0.5;
+constexpr auto kTestMaxID = std::numeric_limits<uint64_t>::max() / 2 + 1;
+constexpr auto kTestDefaultMaxOperations = 10;
+
+const Tag testProbablisticExpectedTags[] = {
+    { "sampler.type", "probabilistic" }, { "sampler.param", 0.5 }
+};
+
+const Tag testLowerBoundExpectedTags[] = { { "sampler.type", "lowerbound" },
+                                           { "sampler.param", 0.5 } };
+
+#define CMP_TAGS(tagArr, tagVec)                                               \
+    {                                                                          \
+        ASSERT_EQ(sizeof(tagArr) / sizeof(Tag), (tagVec).size());              \
+        for (auto i = static_cast<size_t>(0); i < (tagVec).size(); ++i) {      \
+            jaegertracing::thrift::Tag thriftTagArr;                           \
+            jaegertracing::thrift::Tag thriftTagVec;                           \
+            (tagArr)[i].thrift(thriftTagArr);                                  \
+            (tagVec)[i].thrift(thriftTagVec);                                  \
+            ASSERT_EQ(thriftTagArr, thriftTagVec);                             \
+        }                                                                      \
+    }
+
+}  // anonymous namespace
+
+TEST(Sampler, testSamplerTags)
+{
+    ConstSampler constTrue(true);
+    ConstSampler constFalse(false);
+    ProbabilisticSampler prob(0.1);
+    RateLimitingSampler rate(0.1);
+
+    const struct {
+        Sampler& _sampler;
+        std::string _samplerType;
+        Tag::ValueType _samplerParam;
+    } tests[] = { { constTrue, "const", true },
+                  { constFalse, "const", false },
+                  { prob, "probabilistic", 0.1 },
+                  { rate, "ratelimiting", 0.1 } };
+
+    for (auto&& test : tests) {
+        const auto tags =
+            test._sampler.isSampled(TraceID(), kTestOperationName).tags();
+        auto count = 0;
+        for (auto&& tag : tags) {
+            if (tag.key() == kSamplerTypeTagKey) {
+                ASSERT_TRUE(tag.value().is<const char*>());
+                ASSERT_EQ(test._samplerType, tag.value().get<const char*>());
+                ++count;
+            }
+            else if (tag.key() == kSamplerParamTagKey) {
+                ASSERT_EQ(test._samplerParam, tag.value());
+                ++count;
+            }
+        }
+        ASSERT_EQ(2, count);
+    }
+}
+
+TEST(Sampler, testProbabilisticSamplerErrors)
+{
+    ProbabilisticSampler sampler(-0.1);
+    ASSERT_LE(0, sampler.samplingRate());
+    ASSERT_GE(1, sampler.samplingRate());
+    sampler = ProbabilisticSampler(1.1);
+    ASSERT_LE(0, sampler.samplingRate());
+    ASSERT_GE(1, sampler.samplingRate());
+}
+
+TEST(Sampler, testProbabilisticSampler)
+{
+    {
+        ProbabilisticSampler sampler(0.5);
+        auto result =
+            sampler.isSampled(TraceID(0, kTestMaxID + 10), kTestOperationName);
+        ASSERT_FALSE(result.isSampled());
+        CMP_TAGS(testProbablisticExpectedTags, result.tags());
+
+        result =
+            sampler.isSampled(TraceID(0, kTestMaxID - 20), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+        CMP_TAGS(testProbablisticExpectedTags, result.tags());
+    }
+    {
+        ProbabilisticSampler sampler(1.0);
+        auto result =
+            sampler.isSampled(TraceID(0, kTestMaxID), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+
+        result =
+            sampler.isSampled(TraceID(0, kTestMaxID - 20), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+    }
+}
+
+TEST(Sampler, testProbabilisticSamplerPerformance)
+{
+    constexpr auto kNumSamples = static_cast<uint64_t>(10000);
+
+    ProbabilisticSampler sampler(0.001);
+    std::random_device randomDevice;
+    std::default_random_engine randomGenerator(randomDevice());
+    std::uniform_int_distribution<uint64_t> distribution;
+    auto count = static_cast<uint64_t>(0);
+    for (auto i = static_cast<uint64_t>(0); i < kNumSamples; ++i) {
+        TraceID id(0, distribution(randomGenerator));
+        if (sampler.isSampled(id, kTestOperationName).isSampled()) {
+            ++count;
+        }
+    }
+    const auto rate = static_cast<double>(count) / kNumSamples;
+    std::cout << "Sampled: " << count << " rate=" << rate << '\n';
+}
+
+TEST(Sampler, testProbabilisticSamplerInvalidRate)
+{
+    Config samplerConfig1(kSamplerTypeProbabilistic,
+                          1.1,
+                          "",
+                          0,
+                          samplers::Config::Clock::duration());
+    Config samplerConfig2(kSamplerTypeProbabilistic,
+                          -0.1,
+                          "",
+                          0,
+                          samplers::Config::Clock::duration());
+    auto logger = logging::nullLogger();
+    auto metrics = metrics::Metrics::makeNullMetrics();
+    ASSERT_THROW(samplerConfig1.makeSampler("test-service", *logger, *metrics),
+                 std::invalid_argument);
+    ASSERT_THROW(samplerConfig2.makeSampler("test-service", *logger, *metrics),
+                 std::invalid_argument);
+}
+
+TEST(Sampler, testRateLimitingSampler)
+{
+    {
+        RateLimitingSampler sampler(2);
+        auto result = sampler.isSampled(TraceID(), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+        result = sampler.isSampled(TraceID(), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+        result = sampler.isSampled(TraceID(), kTestOperationName);
+        ASSERT_FALSE(result.isSampled());
+    }
+
+    {
+        RateLimitingSampler sampler(0.1);
+        auto result = sampler.isSampled(TraceID(), kTestOperationName);
+        ASSERT_TRUE(result.isSampled());
+        result = sampler.isSampled(TraceID(), kTestOperationName);
+        ASSERT_FALSE(result.isSampled());
+    }
+}
+
+TEST(Sampler, testGuaranteedThroughputProbabilisticSamplerUpdate)
+{
+    auto lowerBound = 2.0;
+    auto samplingRate = 0.5;
+    GuaranteedThroughputProbabilisticSampler sampler(lowerBound, samplingRate);
+    ASSERT_EQ(lowerBound, sampler.lowerBound());
+    ASSERT_EQ(samplingRate, sampler.samplingRate());
+
+    auto newLowerBound = 1.0;
+    auto newSamplingRate = 0.6;
+    sampler.update(newLowerBound, newSamplingRate);
+    ASSERT_EQ(newLowerBound, sampler.lowerBound());
+    ASSERT_EQ(newSamplingRate, sampler.samplingRate());
+
+    newSamplingRate = 1.1;
+    sampler.update(newLowerBound, newSamplingRate);
+    ASSERT_EQ(1.0, sampler.samplingRate());
+}
+
+TEST(Sampler, testAdaptiveSampler)
+{
+    namespace thriftgen = sampling_manager::thrift;
+
+    thriftgen::OperationSamplingStrategy strategy;
+    strategy.__set_operation(kTestOperationName);
+    thriftgen::ProbabilisticSamplingStrategy probabilisticSampling;
+    probabilisticSampling.__set_samplingRate(kTestDefaultSamplingProbability);
+    strategy.__set_probabilisticSampling(probabilisticSampling);
+
+    thriftgen::PerOperationSamplingStrategies strategies;
+    strategies.__set_defaultSamplingProbability(
+        kTestDefaultSamplingProbability);
+    strategies.__set_defaultLowerBoundTracesPerSecond(1.0);
+    strategies.__set_perOperationStrategies({ strategy });
+
+    AdaptiveSampler sampler(strategies, kTestDefaultMaxOperations);
+    auto result =
+        sampler.isSampled(TraceID(0, kTestMaxID + 10), kTestOperationName);
+    ASSERT_TRUE(result.isSampled());
+    CMP_TAGS(testLowerBoundExpectedTags, result.tags());
+
+    result = sampler.isSampled(TraceID(0, kTestMaxID - 20), kTestOperationName);
+    ASSERT_TRUE(result.isSampled());
+    CMP_TAGS(testProbablisticExpectedTags, result.tags());
+
+    result = sampler.isSampled(TraceID(0, kTestMaxID + 10), kTestOperationName);
+    ASSERT_FALSE(result.isSampled());
+
+    result = sampler.isSampled(TraceID(0, kTestMaxID - 20),
+                               kTestFirstTimeOperationName);
+    ASSERT_TRUE(result.isSampled());
+    CMP_TAGS(testProbablisticExpectedTags, result.tags());
+}
+
+TEST(Sampler, testAdaptiveSamplerErrors)
+{
+    namespace thriftgen = sampling_manager::thrift;
+
+    thriftgen::OperationSamplingStrategy strategy;
+    strategy.__set_operation(kTestOperationName);
+    thriftgen::ProbabilisticSamplingStrategy probabilisticSampling;
+    probabilisticSampling.__set_samplingRate(-0.1);
+    strategy.__set_probabilisticSampling(probabilisticSampling);
+
+    thriftgen::PerOperationSamplingStrategies strategies;
+    strategies.__set_defaultSamplingProbability(
+        kTestDefaultSamplingProbability);
+    strategies.__set_defaultLowerBoundTracesPerSecond(2.0);
+    strategies.__set_perOperationStrategies({ strategy });
+
+    {
+        AdaptiveSampler sampler(strategies, kTestDefaultMaxOperations);
+    }
+
+    {
+        strategies.perOperationStrategies.at(0)
+            .probabilisticSampling.__set_samplingRate(1.1);
+        AdaptiveSampler sampler(strategies, kTestDefaultMaxOperations);
+    }
+}
+
+TEST(Sampler, testAdaptiveSamplerUpdate)
+{
+    namespace thriftgen = sampling_manager::thrift;
+
+    constexpr auto kSamplingRate = 0.1;
+    constexpr auto kLowerBound = 2.0;
+
+    thriftgen::OperationSamplingStrategy strategy;
+    strategy.__set_operation(kTestOperationName);
+    thriftgen::ProbabilisticSamplingStrategy probabilisticSampling;
+    probabilisticSampling.__set_samplingRate(kSamplingRate);
+    strategy.__set_probabilisticSampling(probabilisticSampling);
+
+    thriftgen::PerOperationSamplingStrategies strategies;
+    strategies.__set_defaultSamplingProbability(
+        kTestDefaultSamplingProbability);
+    strategies.__set_defaultLowerBoundTracesPerSecond(kLowerBound);
+    strategies.__set_perOperationStrategies({ strategy });
+
+    AdaptiveSampler sampler(strategies, kTestDefaultMaxOperations);
+
+    constexpr auto kNewSamplingRate = 0.2;
+    constexpr auto kNewLowerBound = 3.0;
+    constexpr auto kNewDefaultSamplingProbability = 0.1;
+
+    // Updated kTestOperationName strategy.
+    thriftgen::OperationSamplingStrategy updatedStrategy;
+    updatedStrategy.__set_operation(kTestOperationName);
+    thriftgen::ProbabilisticSamplingStrategy updatedProbabilisticSampling;
+    updatedProbabilisticSampling.__set_samplingRate(kNewSamplingRate);
+    updatedStrategy.__set_probabilisticSampling(updatedProbabilisticSampling);
+
+    // New kTestFirstTimeOperationName strategy.
+    thriftgen::OperationSamplingStrategy newStrategy;
+    newStrategy.__set_operation(kTestFirstTimeOperationName);
+    thriftgen::ProbabilisticSamplingStrategy newProbabilisticSampling;
+    newProbabilisticSampling.__set_samplingRate(kNewSamplingRate);
+    newStrategy.__set_probabilisticSampling(newProbabilisticSampling);
+
+    thriftgen::PerOperationSamplingStrategies newStrategies;
+    newStrategies.__set_defaultSamplingProbability(
+        kNewDefaultSamplingProbability);
+    newStrategies.__set_defaultLowerBoundTracesPerSecond(kNewLowerBound);
+    newStrategies.__set_perOperationStrategies(
+        { updatedStrategy, newStrategy });
+
+    sampler.update(newStrategies);
+}
+
+TEST(Sampler, testRemotelyControlledSampler)
+{
+    const auto mockAgent = testutils::MockAgent::make();
+    mockAgent->start();
+    const auto logger = logging::nullLogger();
+    const auto metrics = metrics::Metrics::makeNullMetrics();
+            
+    // Make sure remote sampling probability is 1
+    sampling_manager::thrift::SamplingStrategyResponse config;
+    config.__set_strategyType(
+        sampling_manager::thrift::SamplingStrategyType::PROBABILISTIC);
+    sampling_manager::thrift::ProbabilisticSamplingStrategy probaStrategy;
+    probaStrategy.__set_samplingRate(1.0);
+    config.__set_probabilisticSampling(probaStrategy);
+    mockAgent->addSamplingStrategy("test-service", config);
+
+    // Default probability of 0.5, switches to 1 when downloaded
+    RemotelyControlledSampler sampler(
+        "test-service",
+        "http://" + mockAgent->samplingServerAddress().authority(),
+        std::make_shared<ProbabilisticSampler>(kTestDefaultSamplingProbability),
+        kTestDefaultMaxOperations,
+        std::chrono::milliseconds(100),
+        *logger,
+        *metrics);
+    
+    // Wait a bit for remote config download to be done
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::random_device device;
+    std::mt19937_64 rng;
+    rng.seed(device());
+    for (auto startTime = RemotelyControlledSampler::Clock::now();
+         std::chrono::duration_cast<std::chrono::seconds>(
+             RemotelyControlledSampler::Clock::now() - startTime)
+             .count() < 1;) {
+        TraceID traceID(rng(), rng());
+        // If probability was 0.5 we could reasonnably assume one of 50 samples fail
+        ASSERT_TRUE(sampler.isSampled(traceID, kTestOperationName).isSampled());
+        std::this_thread::sleep_for(std::chrono::milliseconds(20));
+    }
+    sampler.close();
+}
+
+}  // namespace samplers
+}  // namespace jaegertracing