Skip to content

Commit b6bfb74

Browse files
committed
implement parent-based & ratio-based samplers
Signed-off-by: Ahmad Karimi <[email protected]>
1 parent dab1fcc commit b6bfb74

24 files changed

+1266
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
syntax = "proto3";
2+
3+
package envoy.extensions.tracers.opentelemetry.samplers.v3;
4+
5+
import "envoy/config/core/v3/extension.proto";
6+
7+
import "udpa/annotations/status.proto";
8+
9+
option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.samplers.v3";
10+
option java_outer_classname = "ParentBasedSamplerProto";
11+
option java_multiple_files = true;
12+
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/samplers/v3;samplersv3";
13+
option (udpa.annotations.file_status).package_version_status = ACTIVE;
14+
15+
// [#protodoc-title: Parent Based Sampler config]
16+
// Configuration for the "ParentBased" Sampler extension.
17+
// The sampler follows the "ParentBased" implementation from the OpenTelemetry
18+
// SDK specification.
19+
//
20+
// See:
21+
// `ParentBased sampler specification <https://opentelemetry.io/docs/specs/otel/trace/sdk/#parentbased>`_
22+
// [#extension: envoy.tracers.opentelemetry.samplers.parent_based]
23+
24+
message ParentBasedSamplerConfig {
25+
// Specifies the sampler to be used by the this sampler.
26+
// The configured sampler will be used if the parent trace ID is not passed to Envoy
27+
//
28+
// required
29+
// [#extension-category: envoy.tracers.opentelemetry.samplers]
30+
config.core.v3.TypedExtensionConfig wrapped_sampler = 1;
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
syntax = "proto3";
2+
3+
package envoy.extensions.tracers.opentelemetry.samplers.v3;
4+
5+
import "udpa/annotations/status.proto";
6+
7+
option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.samplers.v3";
8+
option java_outer_classname = "TraceIdRatioBasedSamplerProto";
9+
option java_multiple_files = true;
10+
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/samplers/v3;samplersv3";
11+
option (udpa.annotations.file_status).package_version_status = ACTIVE;
12+
13+
// [#protodoc-title: Trace Id Ratio Based Sampler config]
14+
// Configuration for the "TraceIdRatioBased" Sampler extension.
15+
// The sampler follows the "TraceIdRatioBased" implementation from the OpenTelemetry
16+
// SDK specification.
17+
//
18+
// See:
19+
// `TraceIdRatioBased sampler specification <https://opentelemetry.io/docs/specs/otel/trace/sdk/#traceidratiobased>`_
20+
// [#extension: envoy.tracers.opentelemetry.samplers.trace_id_ratio_based]
21+
22+
message TraceIdRatioBasedSamplerConfig {
23+
// This is a required value in the [0, 1] interval, If the given trace_id
24+
// falls into a given ratio of all possible trace_id values, ShouldSample will
25+
// return RECORD_AND_SAMPLE.
26+
// required
27+
// [#extension-category: envoy.tracers.opentelemetry.samplers]
28+
double ratio = 1;
29+
}

bazel/repository_locations.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ REPOSITORY_LOCATIONS_SPEC = dict(
600600
"envoy.tracers.opentelemetry",
601601
"envoy.tracers.opentelemetry.samplers.always_on",
602602
"envoy.tracers.opentelemetry.samplers.dynatrace",
603+
"envoy.tracers.opentelemetry.samplers.parent_based",
604+
"envoy.tracers.opentelemetry.samplers.trace_id_ratio_based",
603605
],
604606
release_date = "2024-10-07",
605607
cpe = "N/A",

source/extensions/extensions_build_config.bzl

+4-2
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,10 @@ EXTENSIONS = {
294294
# OpenTelemetry tracer samplers
295295
#
296296

297-
"envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config",
298-
"envoy.tracers.opentelemetry.samplers.dynatrace": "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config",
297+
"envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config",
298+
"envoy.tracers.opentelemetry.samplers.dynatrace": "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config",
299+
"envoy.tracers.opentelemetry.samplers.parent_based": "//source/extensions/tracers/opentelemetry/samplers/parent_based:config",
300+
"envoy.tracers.opentelemetry.samplers.trace_id_ratio_based": "//source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based:config",
299301

300302
#
301303
# Transport sockets

source/extensions/extensions_metadata.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,20 @@ envoy.tracers.opentelemetry.samplers.always_on:
12361236
status: wip
12371237
type_urls:
12381238
- envoy.extensions.tracers.opentelemetry.samplers.v3.AlwaysOnSamplerConfig
1239+
envoy.tracers.opentelemetry.samplers.parent_based:
1240+
categories:
1241+
- envoy.tracers.opentelemetry.samplers
1242+
security_posture: unknown
1243+
status: wip
1244+
type_urls:
1245+
- envoy.extensions.tracers.opentelemetry.samplers.v3.ParentBasedSamplerConfig
1246+
envoy.tracers.opentelemetry.samplers.trace_id_ratio_based:
1247+
categories:
1248+
- envoy.tracers.opentelemetry.samplers
1249+
security_posture: unknown
1250+
status: wip
1251+
type_urls:
1252+
- envoy.extensions.tracers.opentelemetry.samplers.v3.TraceIdRatioBasedSamplerConfig
12391253
envoy.tracers.opentelemetry.samplers.dynatrace:
12401254
categories:
12411255
- envoy.tracers.opentelemetry.samplers
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
load(
2+
"//bazel:envoy_build_system.bzl",
3+
"envoy_cc_extension",
4+
"envoy_cc_library",
5+
"envoy_extension_package",
6+
)
7+
8+
licenses(["notice"]) # Apache 2
9+
10+
envoy_extension_package()
11+
12+
envoy_cc_extension(
13+
name = "config",
14+
srcs = ["config.cc"],
15+
hdrs = ["config.h"],
16+
deps = [
17+
":parent_based_sampler_lib",
18+
"//envoy/registry",
19+
"//source/common/config:utility_lib",
20+
"//source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based:config",
21+
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
22+
],
23+
)
24+
25+
envoy_cc_library(
26+
name = "parent_based_sampler_lib",
27+
srcs = ["parent_based_sampler.cc"],
28+
hdrs = ["parent_based_sampler.h"],
29+
deps = [
30+
"//source/extensions/tracers/opentelemetry:opentelemetry_tracer_lib",
31+
"//source/extensions/tracers/opentelemetry/samplers:sampler_lib",
32+
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
33+
],
34+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "source/extensions/tracers/opentelemetry/samplers/parent_based/config.h"
2+
3+
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/parent_based_sampler.pb.validate.h"
4+
#include "envoy/server/tracer_config.h"
5+
6+
#include "source/common/config/utility.h"
7+
#include "source/extensions/tracers/opentelemetry/samplers/parent_based/parent_based_sampler.h"
8+
#include "source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based/config.h"
9+
10+
namespace Envoy {
11+
namespace Extensions {
12+
namespace Tracers {
13+
namespace OpenTelemetry {
14+
15+
SamplerSharedPtr
16+
ParentBasedSamplerFactory::createSampler(const Protobuf::Message& config,
17+
Server::Configuration::TracerFactoryContext& context) {
18+
auto mptr = Envoy::Config::Utility::translateAnyToFactoryConfig(
19+
dynamic_cast<const ProtobufWkt::Any&>(config), context.messageValidationVisitor(), *this);
20+
const auto& proto_config = MessageUtil::downcastAndValidate<
21+
const envoy::extensions::tracers::opentelemetry::samplers::v3::ParentBasedSamplerConfig&>(
22+
*mptr, context.messageValidationVisitor());
23+
auto* factory =
24+
Envoy::Config::Utility::getFactory<SamplerFactory>(proto_config.wrapped_sampler());
25+
SamplerSharedPtr wrapped_sampler =
26+
factory->createSampler(proto_config.wrapped_sampler().typed_config(), context);
27+
return std::make_shared<ParentBasedSampler>(config, context, wrapped_sampler);
28+
}
29+
30+
/**
31+
* Static registration for the Env sampler factory. @see RegisterFactory.
32+
*/
33+
REGISTER_FACTORY(ParentBasedSamplerFactory, SamplerFactory);
34+
35+
} // namespace OpenTelemetry
36+
} // namespace Tracers
37+
} // namespace Extensions
38+
} // namespace Envoy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/parent_based_sampler.pb.h"
6+
#include "envoy/registry/registry.h"
7+
8+
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"
9+
10+
namespace Envoy {
11+
namespace Extensions {
12+
namespace Tracers {
13+
namespace OpenTelemetry {
14+
15+
/**
16+
* Config registration for the ParentBasedSampler. @see SamplerFactory.
17+
*/
18+
class ParentBasedSamplerFactory : public SamplerFactory {
19+
public:
20+
/**
21+
* @brief Create a Sampler. @see ParentBasedSampler
22+
*
23+
* @param config Protobuf config for the sampler.
24+
* @param context A reference to the TracerFactoryContext.
25+
* @return SamplerSharedPtr
26+
*/
27+
SamplerSharedPtr createSampler(const Protobuf::Message& config,
28+
Server::Configuration::TracerFactoryContext& context) override;
29+
30+
ProtobufTypes::MessagePtr createEmptyConfigProto() override {
31+
return std::make_unique<
32+
envoy::extensions::tracers::opentelemetry::samplers::v3::ParentBasedSamplerConfig>();
33+
}
34+
std::string name() const override { return "envoy.tracers.opentelemetry.samplers.parent_based"; }
35+
};
36+
37+
DECLARE_FACTORY(ParentBasedSamplerFactory);
38+
39+
} // namespace OpenTelemetry
40+
} // namespace Tracers
41+
} // namespace Extensions
42+
} // namespace Envoy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "source/extensions/tracers/opentelemetry/samplers/parent_based/parent_based_sampler.h"
2+
3+
#include <memory>
4+
#include <sstream>
5+
#include <string>
6+
7+
#include "source/extensions/tracers/opentelemetry/span_context.h"
8+
9+
namespace Envoy {
10+
namespace Extensions {
11+
namespace Tracers {
12+
namespace OpenTelemetry {
13+
14+
SamplingResult ParentBasedSampler::shouldSample(const absl::optional<SpanContext> parent_context,
15+
const std::string& trace_id,
16+
const std::string& name, OTelSpanKind kind,
17+
OptRef<const Tracing::TraceContext> trace_context,
18+
const std::vector<SpanContext>& links) {
19+
if (!parent_context.has_value() || parent_context->traceId().empty()) {
20+
return wrapped_sampler_->shouldSample(parent_context, trace_id, name, kind, trace_context,
21+
links);
22+
}
23+
24+
SamplingResult result;
25+
result.tracestate = parent_context.value().tracestate();
26+
if (parent_context->sampled()) {
27+
result.decision = Decision::RecordAndSample;
28+
} else {
29+
result.decision = Decision::Drop;
30+
}
31+
return result;
32+
}
33+
34+
std::string ParentBasedSampler::getDescription() const { return "ParentBasedSampler"; }
35+
36+
} // namespace OpenTelemetry
37+
} // namespace Tracers
38+
} // namespace Extensions
39+
} // namespace Envoy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include <memory>
4+
5+
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/parent_based_sampler.pb.h"
6+
#include "envoy/server/factory_context.h"
7+
8+
#include "source/common/common/logger.h"
9+
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"
10+
11+
namespace Envoy {
12+
namespace Extensions {
13+
namespace Tracers {
14+
namespace OpenTelemetry {
15+
16+
/**
17+
* This is a sampler decorator. If the parent context is empty or doesn't have a valid traceId,
18+
* the ParentBasedSampler will delegate the decision to the wrapped sampler.
19+
* Otherwise, it will decide based on the sampled flag of the parent context:
20+
* if parent_context->sampled -> return RecordAndSample
21+
* else -> return Decision::Drop
22+
* Check https://opentelemetry.io/docs/specs/otel/trace/sdk/#parentbased for the official docs and
23+
* https://github.com/open-telemetry/opentelemetry-cpp/blob/eb2b9753ea2df64079e07d40489388ea1b323108/sdk/src/trace/samplers/parent.cc#L30
24+
* for an official implementation
25+
*/
26+
class ParentBasedSampler : public Sampler, Logger::Loggable<Logger::Id::tracing> {
27+
public:
28+
explicit ParentBasedSampler(const Protobuf::Message& /*config*/,
29+
Server::Configuration::TracerFactoryContext& /*context*/,
30+
SamplerSharedPtr wrapped_sampler)
31+
: wrapped_sampler_(wrapped_sampler) {}
32+
SamplingResult shouldSample(const absl::optional<SpanContext> parent_context,
33+
const std::string& trace_id, const std::string& name,
34+
OTelSpanKind spankind,
35+
OptRef<const Tracing::TraceContext> trace_context,
36+
const std::vector<SpanContext>& links) override;
37+
std::string getDescription() const override;
38+
39+
private:
40+
SamplerSharedPtr wrapped_sampler_;
41+
};
42+
43+
} // namespace OpenTelemetry
44+
} // namespace Tracers
45+
} // namespace Extensions
46+
} // namespace Envoy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
load(
2+
"//bazel:envoy_build_system.bzl",
3+
"envoy_cc_extension",
4+
"envoy_cc_library",
5+
"envoy_extension_package",
6+
)
7+
8+
licenses(["notice"]) # Apache 2
9+
10+
envoy_extension_package()
11+
12+
envoy_cc_extension(
13+
name = "config",
14+
srcs = ["config.cc"],
15+
hdrs = ["config.h"],
16+
deps = [
17+
":trace_id_ratio_based_sampler_lib",
18+
"//envoy/registry",
19+
"//source/common/config:utility_lib",
20+
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
21+
],
22+
)
23+
24+
envoy_cc_library(
25+
name = "trace_id_ratio_based_sampler_lib",
26+
srcs = ["trace_id_ratio_based_sampler.cc"],
27+
hdrs = ["trace_id_ratio_based_sampler.h"],
28+
deps = [
29+
"//source/common/common:safe_memcpy_lib",
30+
"//source/extensions/tracers/opentelemetry:opentelemetry_tracer_lib",
31+
"//source/extensions/tracers/opentelemetry/samplers:sampler_lib",
32+
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
33+
],
34+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based/config.h"
2+
3+
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/trace_id_ratio_based_sampler.pb.h"
4+
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/trace_id_ratio_based_sampler.pb.validate.h"
5+
#include "envoy/server/tracer_config.h"
6+
7+
#include "source/common/config/utility.h"
8+
#include "source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based/trace_id_ratio_based_sampler.h"
9+
10+
namespace Envoy {
11+
namespace Extensions {
12+
namespace Tracers {
13+
namespace OpenTelemetry {
14+
15+
SamplerSharedPtr TraceIdRatioBasedSamplerFactory::createSampler(
16+
const Protobuf::Message& config, Server::Configuration::TracerFactoryContext& context) {
17+
auto mptr = Envoy::Config::Utility::translateAnyToFactoryConfig(
18+
dynamic_cast<const ProtobufWkt::Any&>(config), context.messageValidationVisitor(), *this);
19+
20+
const auto& proto_config =
21+
MessageUtil::downcastAndValidate<const envoy::extensions::tracers::opentelemetry::samplers::
22+
v3::TraceIdRatioBasedSamplerConfig&>(
23+
*mptr, context.messageValidationVisitor());
24+
25+
return std::make_shared<TraceIdRatioBasedSampler>(proto_config, context);
26+
}
27+
28+
/**
29+
* Static registration for the Env sampler factory. @see RegisterFactory.
30+
*/
31+
REGISTER_FACTORY(TraceIdRatioBasedSamplerFactory, SamplerFactory);
32+
33+
} // namespace OpenTelemetry
34+
} // namespace Tracers
35+
} // namespace Extensions
36+
} // namespace Envoy

0 commit comments

Comments
 (0)