Skip to content

Commit

Permalink
Parent-or-else Sampler (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
ziqizh authored Jul 9, 2020
1 parent 0cf5519 commit d2f979b
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 5 deletions.
57 changes: 57 additions & 0 deletions sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
#include "opentelemetry/sdk/trace/sampler.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace trace
{
namespace trace_api = opentelemetry::trace;

/**
* A placeholder class that stores the states of a span.
* Will be replaced by the real SpanContext class once it is implemented.
*/
class Sampler::SpanContext
{
public:
inline explicit SpanContext(bool is_recording, bool sampled_flag)
: is_recording(is_recording), sampled_flag(sampled_flag)
{}

bool is_recording;
bool sampled_flag;
};

/**
* The parent or else sampler is a composite sampler. ParentOrElse(delegateSampler) either respects
* the parent span's sampling decision or delegates to delegateSampler for root spans.
*/
class ParentOrElseSampler : public Sampler
{
public:
explicit ParentOrElseSampler(std::shared_ptr<Sampler> delegate_sampler) noexcept;
/** The decision either respects the parent span's sampling decision or delegates to
* delegateSampler for root spans
* @return Returns NOT_RECORD always
*/
SamplingResult ShouldSample(const SpanContext * parent_context,
trace_api::TraceId trace_id,
nostd::string_view name,
trace_api::SpanKind span_kind,
const trace_api::KeyValueIterable & attributes) noexcept override;

/**
* @return Description MUST be ParentOrElse{delegate_sampler_.getDescription()}
*/
std::string GetDescription() const noexcept override;

private:
const std::shared_ptr<Sampler> delegate_sampler_;
const std::string description_;
};
} // namespace trace
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
2 changes: 1 addition & 1 deletion sdk/src/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc)
add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc samplers/parent_or_else.cc)
41 changes: 41 additions & 0 deletions sdk/src/trace/samplers/parent_or_else.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "opentelemetry/sdk/trace/samplers/parent_or_else.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace trace
{
ParentOrElseSampler::ParentOrElseSampler(std::shared_ptr<Sampler> delegate_sampler) noexcept
: delegate_sampler_(delegate_sampler),
description_("ParentOrElse{" + delegate_sampler->GetDescription() + "}")
{}
SamplingResult ParentOrElseSampler::ShouldSample(
const SpanContext *parent_context,
trace_api::TraceId trace_id,
nostd::string_view name,
trace_api::SpanKind span_kind,
const trace_api::KeyValueIterable &attributes) noexcept
{
if (parent_context == nullptr)
{
// If no parent (root span) exists returns the result of the delegateSampler
return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes);
}
// If parent exists:
if (parent_context->sampled_flag)
{
return {Decision::RECORD_AND_SAMPLE, nullptr};
}
return {Decision::NOT_RECORD, nullptr};
}
std::string ParentOrElseSampler::GetDescription() const noexcept
{
return description_;
}
} // namespace trace
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
15 changes: 12 additions & 3 deletions sdk/test/trace/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ cc_test(
],
)



cc_test(
name = "always_off_sampler_test",
srcs = [
Expand All @@ -64,4 +62,15 @@ cc_test(
"//sdk/src/trace",
"@com_google_googletest//:gtest_main",
],
)
)

cc_test(
name = "parent_or_else_sampler_test",
srcs = [
"parent_or_else_sampler_test.cc",
],
deps = [
"//sdk/src/trace",
"@com_google_googletest//:gtest_main",
],
)
3 changes: 2 additions & 1 deletion sdk/test/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
foreach(testname tracer_provider_test span_data_test simple_processor_test
tracer_test always_off_sampler_test always_on_sampler_test)
tracer_test always_off_sampler_test always_on_sampler_test
parent_or_else_sampler_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace)
Expand Down
50 changes: 50 additions & 0 deletions sdk/test/trace/parent_or_else_sampler_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <gtest/gtest.h>
#include <memory>
#include "opentelemetry/sdk/trace/samplers/always_off.h"
#include "opentelemetry/sdk/trace/samplers/always_on.h"
#include "opentelemetry/sdk/trace/samplers/parent_or_else.h"

using opentelemetry::sdk::trace::AlwaysOffSampler;
using opentelemetry::sdk::trace::AlwaysOnSampler;
using opentelemetry::sdk::trace::Decision;
using opentelemetry::sdk::trace::ParentOrElseSampler;

TEST(ParentOrElseSampler, ShouldSample)
{
ParentOrElseSampler sampler_off(std::make_shared<AlwaysOffSampler>());
ParentOrElseSampler sampler_on(std::make_shared<AlwaysOnSampler>());

// Set up parameters
opentelemetry::trace::TraceId trace_id;
opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal;
using M = std::map<std::string, int>;
M m1 = {{}};
opentelemetry::trace::KeyValueIterableView<M> view{m1};
opentelemetry::sdk::trace::Sampler::SpanContext parent_context_sampled(true, true);
opentelemetry::sdk::trace::Sampler::SpanContext parent_context_nonsampled(true, false);

// Case 1: Parent doesn't exist. Return result of delegateSampler()
auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view);
auto sampling_result2 = sampler_on.ShouldSample(nullptr, trace_id, "", span_kind, view);

ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision);
ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result2.decision);

// Case 2: Parent exists and SampledFlag is true
auto sampling_result3 =
sampler_off.ShouldSample(&parent_context_sampled, trace_id, "", span_kind, view);
ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result3.decision);

// Case 3: Parent exists and SampledFlag is false
auto sampling_result4 =
sampler_on.ShouldSample(&parent_context_nonsampled, trace_id, "", span_kind, view);
ASSERT_EQ(Decision::NOT_RECORD, sampling_result4.decision);
}

TEST(ParentOrElseSampler, GetDescription)
{
ParentOrElseSampler sampler(std::make_shared<AlwaysOffSampler>());
ASSERT_EQ("ParentOrElse{AlwaysOffSampler}", sampler.GetDescription());
ParentOrElseSampler sampler2(std::make_shared<AlwaysOnSampler>());
ASSERT_EQ("ParentOrElse{AlwaysOnSampler}", sampler2.GetDescription());
}

0 comments on commit d2f979b

Please sign in to comment.