Skip to content

Commit 05352f6

Browse files
therealak12wbpcode
andauthored
opentelemetry tracer: implement TraceIDRatioBased and ParentBased samplers (envoyproxy#37787)
Commit Message: implement TraceIDRatioBased and ParentBased samplers Additional Description: [A previous issue](envoyproxy#35016) existed for adding opentelemetry samplers to Envoy so I didn't create a new one. The PR at hand implements two of these samplers. The implementation and testing strategies are inspired by the OTEL's [Go](https://github.com/open-telemetry/opentelemetry-go) and [CPP](https://github.com/open-telemetry/opentelemetry-cpp) SDKs. Risk Level: Low Testing: The PR has unit and integration tests which I've run locally. Docs Changes: Release Notes: Platform Specific Features: --------- Signed-off-by: Ahmad Karimi <[email protected]> Signed-off-by: therealak12 <[email protected]> Co-authored-by: code <[email protected]>
1 parent 1e5bbb5 commit 05352f6

25 files changed

+1375
-4
lines changed

api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ licenses(["notice"]) # Apache 2
77
api_proto_package(
88
deps = [
99
"//envoy/config/core/v3:pkg",
10+
"//envoy/type/v3:pkg",
1011
"@com_github_cncf_xds//udpa/annotations:pkg",
1112
"@com_github_cncf_xds//xds/annotations/v3:pkg",
1213
"@com_github_cncf_xds//xds/type/v3:pkg",
Lines changed: 31 additions & 0 deletions
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 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+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
syntax = "proto3";
2+
3+
package envoy.extensions.tracers.opentelemetry.samplers.v3;
4+
5+
import "envoy/type/v3/percent.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 = "TraceIdRatioBasedSamplerProto";
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: Trace Id Ratio Based Sampler config]
16+
// Configuration for the "TraceIdRatioBased" Sampler extension.
17+
// The sampler follows the "TraceIdRatioBased" implementation from the OpenTelemetry
18+
// SDK specification.
19+
//
20+
// See:
21+
// `TraceIdRatioBased sampler specification <https://opentelemetry.io/docs/specs/otel/trace/sdk/#traceidratiobased>`_
22+
// [#extension: envoy.tracers.opentelemetry.samplers.trace_id_ratio_based]
23+
24+
message TraceIdRatioBasedSamplerConfig {
25+
// If the given trace_id falls into a given percentage of all possible
26+
// trace_id values, ShouldSample will return RECORD_AND_SAMPLE.
27+
// required
28+
// [#extension-category: envoy.tracers.opentelemetry.samplers]
29+
type.v3.FractionalPercent sampling_percentage = 1;
30+
}

bazel/repository_locations.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@ REPOSITORY_LOCATIONS_SPEC = dict(
595595
"envoy.tracers.opentelemetry.samplers.always_on",
596596
"envoy.tracers.opentelemetry.samplers.dynatrace",
597597
"envoy.tracers.opentelemetry.samplers.cel",
598+
"envoy.tracers.opentelemetry.samplers.parent_based",
599+
"envoy.tracers.opentelemetry.samplers.trace_id_ratio_based",
598600
],
599601
release_date = "2025-04-01",
600602
cpe = "N/A",

source/extensions/extensions_build_config.bzl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,11 @@ EXTENSIONS = {
298298
# OpenTelemetry tracer samplers
299299
#
300300

301-
"envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config",
302-
"envoy.tracers.opentelemetry.samplers.dynatrace": "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config",
303-
"envoy.tracers.opentelemetry.samplers.cel": "//source/extensions/tracers/opentelemetry/samplers/cel:config",
301+
"envoy.tracers.opentelemetry.samplers.cel": "//source/extensions/tracers/opentelemetry/samplers/cel:config",
302+
"envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config",
303+
"envoy.tracers.opentelemetry.samplers.dynatrace": "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config",
304+
"envoy.tracers.opentelemetry.samplers.parent_based": "//source/extensions/tracers/opentelemetry/samplers/parent_based:config",
305+
"envoy.tracers.opentelemetry.samplers.trace_id_ratio_based": "//source/extensions/tracers/opentelemetry/samplers/trace_id_ratio_based:config",
304306

305307
#
306308
# Transport sockets

source/extensions/extensions_metadata.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,20 @@ envoy.tracers.opentelemetry.samplers.always_on:
12841284
status: wip
12851285
type_urls:
12861286
- envoy.extensions.tracers.opentelemetry.samplers.v3.AlwaysOnSamplerConfig
1287+
envoy.tracers.opentelemetry.samplers.parent_based:
1288+
categories:
1289+
- envoy.tracers.opentelemetry.samplers
1290+
security_posture: unknown
1291+
status: wip
1292+
type_urls:
1293+
- envoy.extensions.tracers.opentelemetry.samplers.v3.ParentBasedSamplerConfig
1294+
envoy.tracers.opentelemetry.samplers.trace_id_ratio_based:
1295+
categories:
1296+
- envoy.tracers.opentelemetry.samplers
1297+
security_posture: unknown
1298+
status: wip
1299+
type_urls:
1300+
- envoy.extensions.tracers.opentelemetry.samplers.v3.TraceIdRatioBasedSamplerConfig
12871301
envoy.tracers.opentelemetry.samplers.dynatrace:
12881302
categories:
12891303
- envoy.tracers.opentelemetry.samplers
Lines changed: 34 additions & 0 deletions
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+
)
Lines changed: 38 additions & 0 deletions
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::getAndCheckFactory<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
Lines changed: 42 additions & 0 deletions
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
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 StreamInfo::StreamInfo& stream_info,
15+
const absl::optional<SpanContext> parent_context,
16+
const std::string& trace_id,
17+
const std::string& name, OTelSpanKind kind,
18+
OptRef<const Tracing::TraceContext> trace_context,
19+
const std::vector<SpanContext>& links) {
20+
if (!parent_context.has_value() || parent_context->traceId().empty()) {
21+
return wrapped_sampler_->shouldSample(stream_info, parent_context, trace_id, name, kind,
22+
trace_context, links);
23+
}
24+
25+
SamplingResult result;
26+
result.tracestate = parent_context.value().tracestate();
27+
if (parent_context->sampled()) {
28+
result.decision = Decision::RecordAndSample;
29+
} else {
30+
result.decision = Decision::Drop;
31+
}
32+
return result;
33+
}
34+
35+
std::string ParentBasedSampler::getDescription() const { return "ParentBasedSampler"; }
36+
37+
} // namespace OpenTelemetry
38+
} // namespace Tracers
39+
} // namespace Extensions
40+
} // namespace Envoy

0 commit comments

Comments
 (0)