Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sampler interface and AlwaysOnSampler #5

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
"//envoy/extensions/transport_sockets/internal_upstream/v3:pkg",
Expand Down
9 changes: 9 additions & 0 deletions api/envoy/config/trace/v3/opentelemetry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";

package envoy.config.trace.v3;

import "envoy/config/core/v3/extension.proto";
import "envoy/config/core/v3/grpc_service.proto";

import "udpa/annotations/status.proto";
Expand All @@ -25,4 +26,12 @@ message OpenTelemetryConfig {
// The name for the service. This will be populated in the ResourceSpan Resource attributes.
// If it is not provided, it will default to "unknown_service:envoy".
string service_name = 2;

// Specifies the sampler to be used by the OpenTelemetry tracer.
// The configured sampler implements the Sampler interface defined by the OpenTelemetry specification.
// This field can be left empty. In this case, the default Envoy sampling decision is used.
//
// See: `OpenTelemetry sampler specification <https://opentelemetry.io/docs/specs/otel/trace/sdk/#sampler>`_
// [#extension-category: envoy.tracers.opentelemetry.samplers]
core.v3.TypedExtensionConfig sampler = 3;
}
9 changes: 9 additions & 0 deletions api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
syntax = "proto3";

package envoy.extensions.tracers.opentelemetry.samplers.v3;

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.samplers.v3";
option java_outer_classname = "AlwaysOnSamplerProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/samplers/v3;samplersv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Always On Sampler config]
// Configuration for the "AlwaysOn" Sampler extension.
// The sampler follows the "AlwaysOn" implementation from the OpenTelemetry
// SDK specification.
//
// See:
// `AlwaysOn sampler specification <https://opentelemetry.io/docs/specs/otel/trace/sdk/#alwayson>`_
// [#extension: envoy.tracers.opentelemetry.samplers.always_on]

message AlwaysOnSamplerConfig {
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
"//envoy/extensions/transport_sockets/internal_upstream/v3:pkg",
Expand Down
10 changes: 10 additions & 0 deletions docs/root/api-v3/config/trace/opentelemetry/samplers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
OpenTelemetry Samplers
======================

Samplers that can be configured with the OpenTelemetry Tracer:

.. toctree::
:glob:
:maxdepth: 3

../../../extensions/tracers/opentelemetry/samplers/v3/*
1 change: 1 addition & 0 deletions docs/root/api-v3/config/trace/trace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ HTTP tracers
:maxdepth: 2

v3/*
opentelemetry/samplers
6 changes: 6 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ EXTENSIONS = {
"envoy.tracers.skywalking": "//source/extensions/tracers/skywalking:config",
"envoy.tracers.opentelemetry": "//source/extensions/tracers/opentelemetry:config",

#
# OpenTelemetry tracer samplers
#

"envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config",

#
# Transport sockets
#
Expand Down
5 changes: 5 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,11 @@ envoy.tracers.opentelemetry:
status: wip
type_urls:
- envoy.config.trace.v3.OpenTelemetryConfig
envoy.tracers.opentelemetry.samplers.always_on:
categories:
- envoy.tracers.opentelemetry.samplers
security_posture: unknown
status: wip
envoy.tracers.skywalking:
categories:
- envoy.tracers
Expand Down
1 change: 1 addition & 0 deletions source/extensions/tracers/opentelemetry/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ envoy_cc_library(
"//source/common/config:utility_lib",
"//source/common/tracing:http_tracer_lib",
"//source/extensions/tracers/common:factory_base_lib",
"//source/extensions/tracers/opentelemetry/samplers:sampler_lib",
"@envoy_api//envoy/config/trace/v3:pkg_cc_proto",
"@opentelemetry_proto//:trace_cc_proto",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "source/common/common/logger.h"
#include "source/common/config/utility.h"
#include "source/common/tracing/http_tracer_impl.h"
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"

#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "opentelemetry/proto/trace/v1/trace.pb.h"
Expand All @@ -20,29 +21,54 @@ namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

namespace {

SamplerSharedPtr
tryCreateSamper(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context) {
SamplerSharedPtr sampler;
if (opentelemetry_config.has_sampler()) {
auto& sampler_config = opentelemetry_config.sampler();
auto* factory = Envoy::Config::Utility::getFactory<SamplerFactory>(sampler_config);
if (!factory) {
throw EnvoyException(fmt::format("Sampler factory not found: '{}'", sampler_config.name()));
}
sampler = factory->createSampler(sampler_config.typed_config(), context);
}
return sampler;
}

} // namespace

Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context)
: tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()),
tracing_stats_{OPENTELEMETRY_TRACER_STATS(
POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.opentelemetry"))} {
auto& factory_context = context.serverFactoryContext();

// Create the sampler if configured
SamplerSharedPtr sampler = tryCreateSamper(opentelemetry_config, context);

// Create the tracer in Thread Local Storage.
tls_slot_ptr_->set([opentelemetry_config, &factory_context, this](Event::Dispatcher& dispatcher) {
OpenTelemetryGrpcTraceExporterPtr exporter;
if (opentelemetry_config.has_grpc_service()) {
Grpc::AsyncClientFactoryPtr&& factory =
factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService(
opentelemetry_config.grpc_service(), factory_context.scope(), true);
const Grpc::RawAsyncClientSharedPtr& async_client_shared_ptr =
factory->createUncachedRawAsyncClient();
exporter = std::make_unique<OpenTelemetryGrpcTraceExporter>(async_client_shared_ptr);
}
TracerPtr tracer = std::make_unique<Tracer>(
std::move(exporter), factory_context.timeSource(), factory_context.api().randomGenerator(),
factory_context.runtime(), dispatcher, tracing_stats_, opentelemetry_config.service_name());
tls_slot_ptr_->set(
[opentelemetry_config, &factory_context, this, sampler](Event::Dispatcher& dispatcher) {
OpenTelemetryGrpcTraceExporterPtr exporter;
if (opentelemetry_config.has_grpc_service()) {
Grpc::AsyncClientFactoryPtr&& factory =
factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService(
opentelemetry_config.grpc_service(), factory_context.scope(), true);
const Grpc::RawAsyncClientSharedPtr& async_client_shared_ptr =
factory->createUncachedRawAsyncClient();
exporter = std::make_unique<OpenTelemetryGrpcTraceExporter>(async_client_shared_ptr);
}
TracerPtr tracer = std::make_unique<Tracer>(
std::move(exporter), factory_context.timeSource(),
factory_context.api().randomGenerator(), factory_context.runtime(), dispatcher,
tracing_stats_, opentelemetry_config.service_name(), sampler);

return std::make_shared<TlsTracer>(std::move(tracer));
});
return std::make_shared<TlsTracer>(std::move(tracer));
});
}

Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config,
Expand All @@ -57,7 +83,6 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config,
// No propagation header, so we can create a fresh span with the given decision.
Tracing::SpanPtr new_open_telemetry_span =
tracer.startSpan(config, operation_name, stream_info.startTime(), tracing_decision);
new_open_telemetry_span->setSampled(tracing_decision.traced);
return new_open_telemetry_span;
} else {
// Try to extract the span context. If we can't, just return a null span.
Expand Down
25 changes: 25 additions & 0 deletions source/extensions/tracers/opentelemetry/samplers/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_library(
name = "sampler_lib",
srcs = [
],
hdrs = [
"sampler.h",
],
deps = [
"//envoy/config:typed_config_interface",
"//envoy/server:tracer_config_interface",
"//source/common/common:logger_lib",
"//source/common/config:utility_lib",
"@opentelemetry_proto//:trace_cc_proto",
],
)
33 changes: 33 additions & 0 deletions source/extensions/tracers/opentelemetry/samplers/always_on/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
deps = [
":always_on_sampler_lib",
"//envoy/registry",
"//source/common/config:utility_lib",
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
],
)

envoy_cc_library(
name = "always_on_sampler_lib",
srcs = ["always_on_sampler.cc"],
hdrs = ["always_on_sampler.h"],
deps = [
"//source/common/config:datasource_lib",
"//source/extensions/tracers/opentelemetry:opentelemetry_tracer_lib",
"//source/extensions/tracers/opentelemetry/samplers:sampler_lib",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h"

#include <memory>
#include <sstream>
#include <string>

#include "source/common/config/datasource.h"
#include "source/extensions/tracers/opentelemetry/span_context.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

SamplingResult
AlwaysOnSampler::shouldSample(const absl::optional<SpanContext> parent_context,
const std::string& /*trace_id*/, const std::string& /*name*/,
::opentelemetry::proto::trace::v1::Span::SpanKind /*kind*/,
const std::map<std::string, std::string>& /*attributes*/,
const std::vector<SpanContext>& /*links*/) {
SamplingResult result;
result.decision = Decision::RECORD_AND_SAMPLE;
if (parent_context.has_value()) {
result.tracestate = parent_context.value().tracestate();
}
return result;
}

std::string AlwaysOnSampler::getDescription() const { return "AlwaysOnSampler"; }

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include "envoy/server/factory_context.h"

#include "source/common/common/logger.h"
#include "source/common/config/datasource.h"
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

/**
* @brief A sampler which samples every span.
* https://opentelemetry.io/docs/specs/otel/trace/sdk/#alwayson
* - Returns RECORD_AND_SAMPLE always.
* - Description MUST be AlwaysOnSampler.
*
*/
class AlwaysOnSampler : public Sampler, Logger::Loggable<Logger::Id::tracing> {
public:
explicit AlwaysOnSampler(const Protobuf::Message& /*config*/,
Server::Configuration::TracerFactoryContext& /*context*/) {}
SamplingResult shouldSample(const absl::optional<SpanContext> parent_context,
const std::string& trace_id, const std::string& name,
::opentelemetry::proto::trace::v1::Span::SpanKind spankind,
const std::map<std::string, std::string>& attributes,
const std::vector<SpanContext>& links) override;
std::string getDescription() const override;

private:
};

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "source/extensions/tracers/opentelemetry/samplers/always_on/config.h"

#include "envoy/server/tracer_config.h"

#include "source/common/config/utility.h"
#include "source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

SamplerSharedPtr
AlwaysOnSamplerFactory::createSampler(const Protobuf::Message& config,
Server::Configuration::TracerFactoryContext& context) {
return std::make_shared<AlwaysOnSampler>(config, context);
}

/**
* Static registration for the Env sampler factory. @see RegisterFactory.
*/
REGISTER_FACTORY(AlwaysOnSamplerFactory, SamplerFactory);

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Loading